强制Parallel.ForEach为集合中的每个项目创建一个线程

时间:2012-02-15 08:25:12

标签: c# .net parallel-processing

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

        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秒的工作?

1 个答案:

答案 0 :(得分:3)

如果你的约束是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()