使用多线程加速.NET反射

时间:2009-05-04 04:13:27

标签: .net multithreading reflection multicore

我的电脑有一个双核CPU,我想知道 - 如果我开始在两个线程中处理,是否可以将.NET反射时间减少两个。

通过“处理”,我的意思如下:

1.装载组件 2.忘记所有类型(.GetTypes()) 3.处理这些类型 4.为这些方法挑选这些类型 等

如果是的话 - 什么是最好的(表现明智的)策略:

  1. 在一个线程中加载所有程序集,然后在两个concurent线程中处理metainfo
  2. 在自己的线程中加载和处理每个程序集

3 个答案:

答案 0 :(得分:3)

要记住以下几点:

  • 启动一个新线程是很昂贵的,所以如果任务是短暂的,那么开销可能会过高。通过使用线程池而不是启动自己的线程,线程池将确保尽可能地重用线程。但是,在当前线程池实现中,在短时间内启动大量任务不会产生最佳结果。

  • 由于您的特定任务涉及一些I / O,这可能是操作中最昂贵的部分。分离几个线程以等待I / O可能无法产生更好的性能。在测量它之前你无法确定。

  • 如果您将数据存储在共享存储库中或输出到文件/屏幕,则必须同步。这显然会降低并发性。

答案 1 :(得分:1)

在单独的线程中加载和处理每个程序集更快。但只是快一点。例如,通过缓存MethodInfos可以获得更好的成功。

我会质疑是否需要这样的优化。

结果:

warm up single threaded Time Elapsed 465 ms
multi threaded Time Elapsed 173 ms
single threaded Time Elapsed 456 ms
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Diagnostics;

namespace ConsoleApplication12 {
    class Program {


        static void TimeAction(string description, Action func) {
            var watch = new Stopwatch();
            watch.Start();
            func();
            watch.Stop();
            Console.Write(description);
            Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
        }

        static void Main(string[] args) {

            var assemblies = AppDomain.CurrentDomain.GetAssemblies();

            // warm up 
            TimeAction("warm up single threaded", () =>
            {
                foreach (var assembly in assemblies) {
                    assembly.GetTypes().Select(type => type.GetMethods()).ToArray();
                }

            });

            List<Thread> threads = new List<Thread>();

            TimeAction("multi threaded", () => {
                foreach (var assembly in assemblies) {
                    Thread t = new Thread(new ThreadStart( () => 
                        assembly.GetTypes().Select(type => type.GetMethods()).ToArray()
                        ));
                    t.Start();
                    threads.Add(t);
                }

                foreach (var thread in threads) {
                    thread.Join();
                }
            });

            TimeAction("single threaded", () =>
            {
                foreach (var assembly in assemblies) {
                    assembly.GetTypes().Select(type => type.GetMethods()).ToArray();
                }

            });

            Console.ReadKey();
        }
    }
}

答案 2 :(得分:1)

除非你正在处理绝对庞大的库,否则根据我的经验,反射加载并不是一件非常慢的事情。这可能会浪费你的时间。

尽管如此,请查看ThreadPool.QueueUserWorkItem,使这些内容变得简单。

foreach (Assembly a in "folder/something") {
    ThreadPool.QueueUserWorkItem((object assem) => {
        // do work
    }, a);
}