Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 执行多个线程的最有效方法 您可以跳过此部分:_C#_Multithreading_Performance_Threadpool - Fatal编程技术网

C# 执行多个线程的最有效方法 您可以跳过此部分:

C# 执行多个线程的最有效方法 您可以跳过此部分:,c#,multithreading,performance,threadpool,C#,Multithreading,Performance,Threadpool,我正在创建一个应用程序,客户机需要在其中找到同一网络上的服务器 服务器: 公共静态侦听(Int32端口) { } 假设服务器正在侦听端口12345 然后客户端: 获取客户端的当前ip地址,假设它是192.168.5.88 创建所有可能ip地址的列表。如果服务器ip地址与客户端ip地址位于同一本地网络上,则它们可能与客户端ip地址相关,因此我将列表构造为: 192.168.5.0 192.168.5.1 192.168.5.2 192.168.5.3 .....et

我正在创建一个应用程序,客户机需要在其中找到同一网络上的服务器

服务器:

公共静态侦听(Int32端口) {

}

假设服务器正在侦听端口12345

然后客户端:

  • 获取客户端的当前ip地址,假设它是192.168.5.88
  • 创建所有可能ip地址的列表。如果服务器ip地址与客户端ip地址位于同一本地网络上,则它们可能与客户端ip地址相关,因此我将列表构造为:

       192.168.5.0
       192.168.5.1
       192.168.5.2
       192.168.5.3
       .....etc
       .....
       192.168.0.88
       192.168.1.88
       192.168.2.88
       192.168.3.88
       ...etc
       192.0.5.88 
       192.1.5.88
       192.2.5.88
       192.3.5.88
       192.4.5.88
       ..... etc
       0.168.5.88
       1.168.5.88
       2.168.5.88
       3.168.5.88
       4.168.5.88
       .... etc       
    
然后我尝试连接所有可能的ip和端口12345。如果一个连接成功,那么这意味着我找到了服务器的地址


现在我的问题是: 现在我用两种方法来做这件事。我只知道线程的基本知识,我不知道这是否危险,但它的工作速度非常快

        // first way
        foreach (var ip in ListOfIps)
        {               
            new Thread(new ThreadStart(() =>
            {
                TryConnect(ip);
            })).Start();
        }
第二种方式我相信它更安全,但它需要更多的时间:

        // second way
        foreach (var ip in ListOfIps)
        {               
            ThreadPool.QueueUserWorkItem(new WaitCallback(TryConnect), ip);
        }
我必须调用TryConnect方法大约1000次,每次大约需要2秒(我将连接超时设置为2秒)。什么是最有效、最安全的1000次呼叫方式


编辑2 以下是使用不同技术的结果:

1)使用线程池

花了37秒完成

2)使用线程:

花了12秒完成

3)使用任务:


花了8秒

在这种情况下,我更喜欢使用线程池线程的解决方案,因为创建1000个线程是一项繁重的操作(考虑到每个线程获得的内存)。 但是自从.NET4以来,还有另一种解决方案,它使用类
Task
。 任务是可以并行执行的工作负载。您可以这样定义和运行它们:

var t = Task.Factory.StartNew(() => DoAction());

您不必关心使用的线程数,因为运行时环境会处理这个问题。因此,如果您有可能将工作负载分成更小的包,这些包可以并行执行,我将使用任务来完成这项工作。

在这种情况下,我更喜欢使用线程池线程的解决方案,因为创建1000个线程是一项繁重的操作(考虑到每个线程获得的内存)。 但是自从.NET4以来,还有另一种解决方案,它使用类
Task
。 任务是可以并行执行的工作负载。您可以这样定义和运行它们:

var t = Task.Factory.StartNew(() => DoAction());

您不必关心使用的线程数,因为运行时环境会处理这个问题。因此,如果您有可能将工作负载分成更小的包,这些包可以并行执行,我将使用任务来完成这项工作。

这种方法有其优点和缺点:

  • 在每个连接上使用一个单独的线程(理论上)可以使所有连接并行进行,因为这是一个阻塞I/O操作,所以所有线程都将挂起,直到相应的连接成功。但是,在系统上创建1000个线程有点过分

  • 使用线程池有利于重用线程,但一次只能激活有限数量的连接任务。例如,如果线程池有4个线程,那么将尝试4个连接,然后再尝试4个连接,依此类推。这是轻资源,但可能需要太长时间,因为,正如您所说,单个连接需要大约2秒


  • 因此,我建议进行权衡:创建一个包含大约50个线程的线程池(使用
    SetMaxThreads
    方法)并对所有连接进行排队。这样,它的资源将比1000个线程少,并且处理连接的速度仍然相当快。

    这种方法有其优点和缺点:

  • 在每个连接上使用一个单独的线程(理论上)可以使所有连接并行进行,因为这是一个阻塞I/O操作,所以所有线程都将挂起,直到相应的连接成功。但是,在系统上创建1000个线程有点过分

  • 使用线程池有利于重用线程,但一次只能激活有限数量的连接任务。例如,如果线程池有4个线程,那么将尝试4个连接,然后再尝试4个连接,依此类推。这是轻资源,但可能需要太长时间,因为,正如您所说,单个连接需要大约2秒


  • 因此,我建议进行权衡:创建一个包含大约50个线程的线程池(使用
    SetMaxThreads
    方法)并对所有连接进行排队。这样,它的资源将比1000个线程少,并且处理连接的速度仍然相当快。

    这两种方法都有创建过多线程的风险

    线程的创建时间和内存消耗都很昂贵

    看起来您的第二种方法,使用ThreadPool,应该会更好。由于超时时间较长(2秒),它仍将创建许多线程,但远远少于1000个

    更好的方法(需要FX4)是使用
    Parallel.ForEach(…)
    。但这也可能需要一些调整


    一个真正好的解决方案是使用广播(UDP)协议来发现服务

    这两种方法都有创建太多线程的风险

    线程的创建时间和内存消耗都很昂贵

    看起来您的第二种方法,使用ThreadPool,应该会更好。由于超时时间较长(2秒),它仍将创建许多线程,但远远少于1000个

    更好的方法(需要FX4)是使用
    Parallel.ForEach(…)
    。但这也可能需要一些调整

    一个真正好的解决方案是使用广播(UDP)协议来发现服务

    现在我自己做了
            ..
            ..
            var now = DateTime.Now;
            foreach (var item in allIps)
            {
                new Thread(new ThreadStart(() =>
                {
                    DoWork(item);
    
                })).Start();
    
            }
    
            ThreadPool.QueueUserWorkItem(new WaitCallback(PrintTimeDifference), now);
    
            ..
            ..
            var now = DateTime.Now;
            foreach (var item in allIps)
            {
    
                var t = Task.Factory.StartNew(() =>
    
                    DoWork(item)
                );                                
            }
    
            ThreadPool.QueueUserWorkItem(new WaitCallback(PrintTimeDifference), now);
        }
    
        static void PrintTimeDifference(object startTime)
        {
            Console.WriteLine("------------------Done!----------------------");
            var s = (DateTime)startTime;
            Console.WriteLine((DateTime.Now-s).Seconds);
        }
    
    var t = Task.Factory.StartNew(() => DoAction());
    
    class Program {
        private static long parallelIterations = 100;
        private static long taskIterations = 100000000;
    
        static void Main(string[] args) {
            Console.WriteLine("Parallel Iterations: {0:n0}", parallelIterations);
            Console.WriteLine("Task Iterations: {0:n0}", taskIterations);
            Analyse("Simple Threads", ExecuteWorkWithSimpleThreads);
            Analyse("ThreadPool Threads", ExecuteWorkWithThreadPoolThreads);
            Analyse("Tasks", ExecuteWorkWithTasks);
            Analyse("Parallel For", ExecuteWorkWithParallelFor);
            Analyse("Async Delegates", ExecuteWorkWithAsyncDelegates);
        }
    
        private static void Analyse(string name, Action action) {
            Stopwatch watch = new Stopwatch();
            watch.Start();
    
            action();
    
            watch.Stop();
            Console.WriteLine("{0}: {1} seconds", name.PadRight(20), watch.Elapsed.TotalSeconds);
        }
    
        private static void ExecuteWorkWithSimpleThreads() {
            Thread[] threads = new Thread[parallelIterations];
            for (long i = 0; i < parallelIterations; i++) {
                threads[i] = new Thread(DoWork);
                threads[i].Start();
            }
            for (long i = 0; i < parallelIterations; i++) {
                threads[i].Join();
            }
        }
    
        private static void ExecuteWorkWithThreadPoolThreads() {
            object locker = new object();
            EventWaitHandle waitHandle = new ManualResetEvent(false);
    
            int finished = 0;
            for (long i = 0; i < parallelIterations; i++) {
                ThreadPool.QueueUserWorkItem((threadContext) => {
                    DoWork();
                    lock (locker) {
                        finished++;
                        if (finished == parallelIterations)
                            waitHandle.Set();
                    }
                });
            }
            waitHandle.WaitOne();
        }
    
        private static void ExecuteWorkWithTasks() {
            Task[] tasks = new Task[parallelIterations];
            for (long i = 0; i < parallelIterations; i++) {
                tasks[i] = Task.Factory.StartNew(DoWork);
            }
            Task.WaitAll(tasks);
        }
    
        private static void ExecuteWorkWithParallelFor() {
            Parallel.For(0, parallelIterations, (n) => DoWork());
        }
    
        private static void ExecuteWorkWithAsyncDelegates() {
            Action[] actions = new Action[parallelIterations];
            IAsyncResult[] results = new IAsyncResult[parallelIterations];
    
            for (long i = 0; i < parallelIterations; i++) {
                actions[i] = DoWork;
                results[i] = actions[i].BeginInvoke((result) => { }, null);
            }
            for (long i = 0; i < parallelIterations; i++) {
                results[i].AsyncWaitHandle.WaitOne();
                results[i].AsyncWaitHandle.Close();
            }
        }
    
        private static void DoWork() {
            //Thread.Sleep(TimeSpan.FromMilliseconds(taskDuration));
            for (long i = 0; i < taskIterations; i++ ) { }
        }
    }