我读过线程非常有问题。有哪些替代品?什么能自动处理阻塞和填充?
很多人推荐后台工作者,但我不知道为什么。
任何人都在关心解释“简单”的选择吗?用户可以选择要使用的线程数(取决于它们的速度需求和计算机功率)。
有什么想法吗?
答案 0 :(得分:6)
总结线程的问题:
竞赛的一个例子:假设两个线程共享一些存储号码的内存的访问权限。线程1从存储器地址读取并将其存储在CPU寄存器中。线程2也是如此。现在,线程1递增数字并将其写回内存。线程2然后做同样的事情。结果:数字只增加1,而两个线程都试图递增它。这种相互作用的结果取决于时间。更糟糕的是,你的代码可能看起来没有错误,但是在蓝色的月亮中,时机错了,坏事发生了。
为了避免这些问题,答案很简单:避免共享可写内存。相反,使用消息传递来在线程之间进行通信。一个极端的例子是将线程放在单独的进程中,并通过TCP / IP连接或命名管道进行通信。
另一种方法是只共享只读数据结构,这就是为什么functional programming语言可以在多个线程中很好地工作的原因。
答案 1 :(得分:5)
这是一个更高级别的答案,但如果您想考虑线程的其他替代方案,它可能会有用。无论如何,大多数答案都讨论了基于线程(或线程池)或.NET 4.0任务的解决方案,但还有一个替代方案,称为消息传递。这已成功用于Erlang(爱立信使用的功能语言)。由于功能编程在这些日子里变得越来越主流(例如F#),我想我可以提一下。在一般:
线程(或线程池)通常可用于具有相对长时间运行的计算。当它需要与其他线程共享状态时,它会变得棘手(您必须正确使用锁或其他同步原语)。
任务(在.NET 4.0中的TPL中可用)非常轻量级 - 您可以将程序拆分为数千个任务,然后让运行时运行它们(它将使用最佳数量的线程)。如果你可以使用任务代替线程来编写算法,那么这听起来是个好主意 - 当你使用较小的步骤运行计算时,你可以避免一些同步。
声明性方法(.NET 4.0中的PLINQ是一个很好的选择)如果您有一些可以使用LINQ基元编码的更高级别的数据处理操作,那么您可以使用此技术。运行时将自动并行化您的代码,因为LINQ没有指定完全应该如何评估结果(您只需要说明您希望得到的结果)。
消息传递允许您将两个写入程序作为并发运行的进程执行某些(相对简单的)任务,并通过相互发送消息进行通信。这很棒,因为您可以在没有通常的同步问题的情况下共享某些状态(发送消息)(您只需发送消息,然后执行其他操作或等待消息)。这是Robert Pickering的good introduction to message-passing in F#。
请注意,最后三种技术与函数式编程密切相关 - 在函数式编程中,您以不同的方式设计程序 - 作为返回结果的计算(这使得使用任务更容易)。您还经常编写声明性和更高级别的代码(这使得使用声明性方法更容易)。
在实际实现方面,F#在核心库中有一个很棒的消息传递库。在C#中,您可以使用Concurrency & Coordination Runtime,感觉有点“hacky”,但也可能非常强大(但可能看起来太复杂)。
答案 2 :(得分:2)
.Net 4中的并行编程选项不是一种“简单”的线程使用方式吗?我不确定我对.Net 3.5及更早版本的建议......
Parallel Computing Developer Center的MSDN link链接到Parellel Programming的大量信息,包括视频链接等。
答案 3 :(得分:1)
我可以推荐这个项目。 Smart Thread Pool
项目描述 Smart Thread Pool是一个用C#编写的线程池。它比.NET内置线程池更先进。 以下是线程池功能的列表:
答案 4 :(得分:1)
“有问题”不是我用来描述使用线程的词。 “乏味”是一个更恰当的描述。
如果您不熟悉线程编程,我建议您阅读this thread作为起点。它并非详尽无遗,但有一些很好的介绍性信息。从那里开始,我会继续搜索这个网站和其他编程网站,以获取与您可能遇到的特定线程问题相关的信息。
至于C#中的特定线程选项,这里有一些关于何时使用每个选项的建议。
答案 5 :(得分:1)
每当你引入多个线程时,每次都会运行,你就可以开启race conditions的潜力。要避免这些,您往往需要添加同步,这会增加复杂性,以及deadlocks的潜力。
许多工具使这更容易。 .NET有很多专门用于缓解处理多线程的痛苦的类,包括BackgroundWorker类,这使得运行后台工作和与用户界面交互更加简单。
.NET 4将为解决这个问题做很多事情。 Task Parallel Library和PLINQ极大地方便了多线程的使用。
至于你上次的评论:
用户可以选择要使用的线程数(取决于他们的速度需求和计算机能力)。
.NET中的大多数例程都是基于ThreadPool构建的。在.NET 4中,当使用TPL时,工作负载实际上会在运行时扩展,从而消除了必须指定要使用的线程数的负担。但是,现在有办法做到这一点。
目前,您可以使用ThreadPool.SetMaxThreads来帮助限制生成的线程数。在TPL中,您可以指定ParallelOptions.MaxDegreesOfParallelism,并将ParallelOptions的实例传递到例程中以控制它。当您添加更多处理核心时,默认行为会随着更多线程而扩展,这通常是最佳行为。
答案 6 :(得分:0)
如果您了解导致问题的原因,则线程不会有问题。
对于前。如果您避免静态,您知道要使用哪个API(例如使用synchronized streams),您将避免因使用不当而导致的许多问题。
答案 7 :(得分:0)
如果线程出现问题(如果你有不安全/不受管理的第三方dll不能支持多线程,就会发生这种情况。在这种情况下,可以选择创建一个用于对操作进行排队的机制。即将操作的参数存储到数据库并且一次只能运行它们。这可以在Windows服务中完成。显然这需要更长的时间,但在某些情况下是唯一的选择。
答案 8 :(得分:0)
线程是解决许多问题不可或缺的工具,成熟的开发人员应该知道如何有效地使用它们。但是像许多工具一样,它们可能会导致一些非常难以发现的错误。
不要回避那些有用的东西,因为它可能会导致问题,而是学习和练习,直到你成为多线程应用程序的首选。
一个很好的起点是Joe Albahari的文章:http://www.albahari.com/threading/。