C#在真实世界的应用中进行线程化

时间:2010-08-05 16:03:26

标签: c# multithreading codeplex

毫无疑问,了解线程是非常有趣的,并且有一些非常好的资源可以做到这一点。但是,我的问题是在实际应用程序中将线程明确地应用为设计或开发的一部分。

我在C#中使用了一些广泛使用且结构良好的.NET应用程序,但没有发现明确使用的痕迹。由于这是由CLR管理还是有任何特定原因,没有真正的需要?

此外,任何在广泛使用的.NET应用程序中编码的线程示例。在Codelplex或Gooogle Code也欢迎。

10 个答案:

答案 0 :(得分:5)

最简单的使用线程的地方是在GUI中执行长时间操作,同时保持UI响应。

如果在UI线程上执行操作,整个GUI将冻结,直到完成。 (因为它不会运行消息循环)
通过在后台线程上执行它,UI将保持响应。

BackgroundWorker类在这里非常有用。

答案 1 :(得分:4)

  

是在实际应用程序中作为设计或开发的一部分明确应用的线程。

为了充分利用现代的多核系统,线程必须从一开始就是设计的一部分。虽然很容易(特别是在.NET 4中)找到要进行线程化的小部分代码,但要获得真正的可伸缩性,您需要设计算法来处理线程,最好是在代码中的“高级”。在设计阶段完成的越早,就越容易正确地将线程构建到应用程序中。

  

由于这是由CLR管理还是没有任何特殊原因?

肯定有需要。线程不是免费的 - 它必须由开发人员添加。这种情况经常发现的主要原因,特别是在开源代码中,实际上更是一个难点。即使使用.NET 4,也难以正确地设计算法以可扩展,安全的方式进行线程化。

答案 2 :(得分:3)

这完全取决于应用程序。

对于需要执行任何重要工作的客户端应用程序(或执行其他可能长时间运行的任务,例如进行Web服务调用),我希望使用后台线程。这可以通过BackgroundWorker,显式使用线程池,显式使用Parallel Extensions或显式创建新线程来实现。

根据我的经验,Web服务和Web应用程序创建自己的线程的可能性要小一些。您更有可能将每个请求有效地视为具有单独的线程(即使ASP.NET在内部移动它)并同步执行所有操作。当然 Web应用程序,它们可以异步执行或者出于其他原因启动线程 - 但我会说这种情况比客户端应用程序更少。

答案 3 :(得分:2)

.NET并行扩展上肯定是+1。微软在这里做了一些很棒的工作来改进ThreadPool。您曾经拥有一个处理所有任务的全局队列,即使它们是从工作线程生成的。现在,他们为每个工作线程提供了一个无锁的全局队列和本地队列。这是一个非常好的改进。

我不像Parallel.For,Parallel.Foreach和Parallel.Invoke(区域)这样的粉丝,因为我认为它们应该是纯语言扩展而不是类库。显然,我理解为什么我们有这个中间步骤,但是C#不可避免地要获得并发性的语言改进,同样不可避免的是我们必须返回并改变我们的代码以利用它: - )

总的来说,如果您正在考虑在.NET中构建并发应用程序,那么您应该自己去研究并行扩展。我也认为,鉴于这是微软最初的努力,你应该非常直言自己什么对你有用,什么不对,这与你认为你自己的并发技能水平无关。微软肯定在倾听,但我认为还没有那么多人使用Parallel Extensions。我昨天在VSLive Redmond看了一个关于这个话题的会议,并继续对这个团队的工作留下深刻的印象。

披露:我曾经是Visual Studio的营销总监,现在我在一家名为Corensic的初创公司,我们正在构建工具来检测并发应用程序中的错误。

答案 4 :(得分:1)

我见过的大多数真实的线程用法都是简单地避免阻塞 - UI,网络,数据库调用等。

您可能会将其视为BeginXXXEndXXX方法对,delegate.BeginInvoke来电,Control.Invoke来电。

我见过的一些系统,其中线程将是一个福音,实际上使用隔离原则来实现多个“线程”,换句话说,将工作分解为完全不相关的块并将它们彼此独立地处理 - 通过简单地一次运行所有流程,可以自动实现“多线程”(或多核处理)。

我认为可以说你发现很多股票和交易应用程序(数据显示)在很大程度上不需要大规模的平行化,也不总是能够被设计为适合它。我见过的例子都是非常具体的问题。这可能是为什么你没有看到任何明显的实现。

答案 5 :(得分:1)

是否使用显式线程实现的问题通常是其他人在此处提到的设计考虑因素。尝试实现并发作为事后的想法通常需要进行大量的激进和批量更改。

请记住,简单地将线程放入应用程序本身并不会提高性能或速度,因为管理每个线程都有成本,也可能是一些内存开销(更不用说,调试它可能很有趣)

根据我的经验,实现线程设计的最常见的地方是Windows服务(后台应用程序)和具有用例场景的应用程序,其中大量工作可以轻松地分成更小的工作量(并交给线程以异步完成。)

至于示例,您可以查看Microsoft Robotics Studio(据我所知,现在有free version) - 它附带了可再发行组件(我找不到它作为独立下载) Concurrency and Coordination Runtime中有Channel 9的一些报道。

正如其他人所提到的,Parallel Extensions团队(blog is here)在线程安全和并行执行方面做了一些很好的工作,您可以在MSDN Code site上找到一些示例/示例。

答案 6 :(得分:0)

线程用于各种场景,基于网络的任何东西都依赖于线程,无论是显式(套接字)还是隐式(Web服务)。线程保持UI响应。并且具有多个并行运行的Windows服务在处理通过需要处理的队列工作的数据时执行相同的操作。

这些只是我见过的最常见的。

答案 7 :(得分:0)

大多数答案都会在GUI应用程序中引用长时间运行的任务。根据我的经验,另一个非常常见的使用场景是生产者/消费者队列。我们有许多实用程序应用程序,它们必须经常向大量端点执行Web请求等。我们使用生产者/消费者线程模式(通常通过集成自定义线程池)来实现这些任务的高度并行化。

事实上,就在此刻,我正在检查一个将200MB文件上传到200个不同FTP位置的应用程序。我们使用SmartThreadPool并且并行运行最多约50个上传,这允许整个批次在一小时内完成(而不是超过50个小时,所有上传都是连续发生的 - 所以在我们的使用中我们发现几乎直线的线性改进)。

答案 8 :(得分:0)

作为现代程序员,我们喜欢抽象,因此我们通过调用Async方法或BeginInvoke以及在.Net 4中使用BackgroundWorker或PFX之类的东西来使用线程。

但有时需要自己进行线程化。例如,在我构建的Web应用程序中,我有一个我在应用程序中添加的邮件队列,并且有一个发送电子邮件的后台线程。如果线程注意到队列正在快速填充它发送它,则会创建另一个线程,如果它然后看到该线程处于空闲状态则会终止它。这可以通过更高级别的抽象来完成,但我手动完成。

答案 9 :(得分:0)

我无法抗拒边缘情况 - 在一些必须实现高度操作确定性或必须容忍高度操作不确定性的应用中,从最初的架构设计一直考虑线程和过程通过最终交付

案例1 - 对于必须达到极高操作可靠性的系统,可以在投票架构中使用三个完全独立的子系统,使用三种不同的机制 - 每个选民产生3个线程/过程,等待他们得出结论/死亡/被杀,并继续IFF他们都说同样的事情 - 例如 - 复杂的航空神经系统

案例2 - 对于必须处理高度操作不确定性的系统 - 做同样的事情,但是一旦某事/任何东西回到你身边,杀掉落后者并拿出你得到的最佳答案 - 例如 - 复杂的日内交易算法,努力破坏使用它们的业务: - )

相关问题