C#能够实现并行的foreach循环吗?

4

我不确定Parallel.foreach的内部线程处理方式,以及它是否能够保证这样的构造可以正常工作?

Parallel.Foreach(Connections, c =>
    {
        Input in = c.getInput();
        while (in.hasNext()) {
            object o = in.getNext();
            dosomething(o);
        }
    }
);

在这里,in.hasNext() 只是等待输入流中的对象并返回 true。基本上,我可以在并行 foreach 结构中运行一堆无限 while 循环,并保证它们都同时运行。

(对于勇敢的人,我是否可以调整此内容,以便通过添加(和删除,这应该很简单)连接来编辑连接列表,并仍然从列表中的所有连接读取输入)。


这应该可以工作,你尝试一下会发生什么? - James Black
我可以尝试,但我不能保证它永远不会产生竞态条件。给我15分钟来设置一个测试服务器/客户端。 - Raynos
我以为像Java一样快速设置测试服务器/客户端会很容易且快速。但是C#并不是那么好。 - Raynos
如果您要修改Connections集合,那么您可能不想使用Parallel.Foreach,而应该自己创建并跟踪Task实例。Parallel.Foreach助手更适用于在(静态)一组项目上并行执行某些操作的情况。 - James Manning
@Raynos:真的,你需要从阻塞式I/O切换到事件驱动。.NET Begin/End模型用于I/O调用使用了I/O完成端口,在每个连接上使用一个线程要好得多。 - Ben Voigt
@BenVoigt 那是在我还没有领略到非阻塞 IO 的乐趣的时代。现在我已经无法回到阻塞 IO 了! - Raynos
3个回答

0
  1. 使用它的线程数量受限,因此某些元素将一个接一个地处理。

  2. 在枚举时编辑列表是不好的。您可能会收到异常(取决于您使用的列表)

  3. 为什么不为每个连接启动一个新线程?

示例代码:

public ConnectionOpen(data)  
{  
    Connection conn=new ...  
    lock(Connections)  
    {  
         Connections.Add(conn);  
    }  

    new Thread(()=>  
    {  
        Receive(conn);//infinite loop goes here  
    }).Start();  
}  

public ConnectionClose(conn)  
{  
    bool removed=false;  
    lock(Connections)  
    {  
        removed=Connections.Remove(conn);  
    }  
    if(removed) conn.StopReceiving();  
}  

我试图将那段代码格式化得更好一些,但不知何故 StackO 解析器无法处理它。 - Robaticus
有时候在开发过程中,除了代码优化(比如网站),还需要考虑开发速度。你给我的这一部分证明非常宝贵。 - Eon

0
基本上,我可以在并行的foreach结构中运行一堆无限while循环,同时保证它们都会同时运行吗?
不行。只有有限数量的工作线程会同时启动,因此如果您运行的无限循环超过了线程数,最后几个将永远不会运行...

0

从技术上讲,这段代码可以工作,但同时运行的线程数量将会有所不同。

除了并行扩展之外,.NET 4还向线程池添加了“爬坡”和线程注入功能,因此基本上.NET线程池将尝试向Parallel.ForEach循环添加线程,以查看是否完成更多线程,由于您的线程永远不会完成,线程数将会有所变化,但我猜测这将是非理想的。

您可以尝试使用ParallelWhile结构,团队已经在博客中介绍了几种方法,这里是其中之一


并行 while 循环以并行方式运行 while 的 do 块。我正在尝试使用无限循环的 do 块来获取并行 for 循环,以便即使是无限循环,也可以运行 for 循环的每个部分。 - Raynos
我认为你不会在Parallel.ForEach中得到这种行为,听起来你想要同时运行N个线程,其中N很大。你为什么需要这么多线程同时运行呢? - Rick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接