Force Parallel.ForEach为集合中的每个项目生成一个线程

本文关键字:线程 一个 项目 Force ForEach 集合 Parallel | 更新日期: 2023-09-27 18:24:33

以下是我使用的代码示例:

        Stopwatch s = new Stopwatch();
        s.Start();
        ParallelOptions po = new ParallelOptions();
        // hosts contain 23 items
        po.MaxDegreeOfParallelism = hosts.Count();
        Parallel.ForEach(hosts, po, p =>
            {
                using (TcpClient tcpClient = new TcpClient())
                {
                    IAsyncResult result = tcpClient.BeginConnect(p.Value, 80, null, null);
                    WaitHandle timeoutHandler = result.AsyncWaitHandle;
                    try
                    {
                        if (!result.AsyncWaitHandle.WaitOne(1000, false))
                        {
                            tasks.TryAdd(p.Key, new TaskCompleteResult { result = false, exc = new Exception("By timeout") });
                            tcpClient.Close();
                        }
                        else
                        {                             
                            tasks.TryAdd(p.Key, new TaskCompleteResult { result = true, exc = null });
                        }
                        tcpClient.EndConnect(result);
                    }
                    catch (Exception ex)
                    {
                        tasks.TryAdd(p.Key, new TaskCompleteResult { result = false, exc = ex });
                    }
                    finally
                    {
                        timeoutHandler.Close();
                    }
                }
            });
        s.Stop();
        Console.WriteLine(s.Elapsed.TotalSeconds);

所以,正如我所想,它会给我1秒(或者可能2秒,如果我们注意一些开销),但它需要4秒。Parallel.ForEach是从一些预先准备好的线程池中获取线程还是创建新的线程?我怎样才能完成1-2秒的工作?

Force Parallel.ForEach为集合中的每个项目生成一个线程

只有当您的约束是CPU时,线程才真正有用。你所做的只是让很多线程单独什么都不做,什么都不并行。

我会用一种非常不同的方式来处理这个问题。你现在正在做的是:

  • 创建大量线程
  • 每个都创建一个等待句柄,然后阻塞长达1秒

我会扭转局面:

  • 创建大量等待句柄
  • 然后开始阻塞剩余的一秒钟

最简单的(伪代码):

WaitHandle[] handles = ... start all the async tasks...
Thread.Sleep(1000);
foreach(handle)
    handle.WaitOne(0) ... log result

但可能涉及到:

WaitHandle[] handles = ... start all the async tasks...
System.Threading.WaitHandle.WaitAll(handles, 1000);
foreach(handle ...)
    handle.WaitOne(0) ... log result

另外:您可以考虑将new Exception("By timeout")替换为new TimeoutException()