线程的替代品

Jam*_*ery 5 c# multithreading

我读过线程非常有问题.有哪些替代品?什么能自动处理阻塞和填充?

很多人推荐后台工作者,但我不知道为什么.

有人想解释"简单"的替代方案吗?用户将能够选择要使用的线程数(取决于它们的速度需求和计算机功率).

有任何想法吗?

Wim*_*nen 6

总结线程的问题:

  • 如果线程共享内存,则可以获得竞争条件
  • 如果你通过大量使用锁来避免比赛,你就会陷入僵局(参见餐饮哲学家的问题)

竞争的一个示例:假设两个线程共享对存储数字的某个内存的访问.线程1从存储器地址读取并将其存储在CPU寄存器中.线程2也是如此.现在,线程1递增数字并将其写回内存.线程2然后做同样的事情.结果:数字只增加1,而两个线程都试图递增它.这种相互作用的结果取决于时间.更糟糕的是,你的代码可能看起来没有错误,但是一旦在蓝色的月亮中,时机是错误的,坏事就会发生.

为了避免这些问题,答案很简单:避免共享可写内存.相反,使用消息传递来在线程之间进行通信.一个极端的例子是将线程放在单独的进程中,并通过TCP/IP连接或命名管道进行通信.

另一种方法是仅共享只读数据结构,这就是函数式编程语言可以在多个线程中很好地工作的原因.


Tom*_*cek 5

这是一个更高级别的答案,但如果您想考虑线程的其他替代方案,它可能会有用.无论如何,大多数答案都讨论了基于线程(或线程池)或.NET 4.0任务的解决方案,但还有一个替代方案,称为消息传递.这已成功用于Erlang(爱立信使用的功能语言).由于功能编程在这些日子里变得越来越主流(例如F#),我想我可以提一下.在一般情况下:

  • 当你有一些相对长时间运行的计算时,通常可以使用线程(或线程池).当它需要与其他线程共享状态时,它会变得棘手(你必须正确使用锁或其他同步原语).

  • 任务(在.NET 4.0中的TPL中可用)非常轻量级 - 您可以将程序拆分为数千个任务,然后让运行时运行它们(它将使用最佳线程数).如果您可以使用任务而不是线程编写算法,这听起来是个好主意 - 当您使用较小的步骤运行计算时,可以避免某些同步.

  • 声明性方法(.NET 4.0中的PLINQ是一个很好的选择)如果你有一些可以使用LINQ原语编码的更高级别的数据处理操作,那么你可以使用这种技术.运行时会自动并行化的代码,因为LINQ没有规定如何准确地应该评估结果(你刚才说你想要得到什么样的结果).

  • 消息传递允许您将两个写程序作为并发运行的进程执行一些(相对简单的)任务,并通过相互发送消息进行通信.这很好,因为你可以在没有通常的同步问题的情况下共享一些状态(发送消息)(你只需发送消息,然后做其他事情或等待消息).以下是Robert Pickering 对F#中消息传递的一个很好的介绍.

请注意,最后三种技术与函数式编程密切相关 - 在函数式编程中,您以不同的方式设计程序 - 作为返回结果的计算(这使得使用任务更容易).您还经常编写声明性和更高级别的代码(这使得使用声明性方法更容易).

在实际实现方面,F#在核心库中有一个很棒的消息传递库.在C#中,您可以使用并发和协调运行时,它感觉有点"hacky",但也可能非常强大(但可能看起来太复杂).