5

毫无疑问,学习线程是令人着迷的,并且有一些非常好的资源可以做到这一点。但是,我的问题是在实际应用程序中作为设计或开发的一部分明确应用线程。

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

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

4

10 回答 10

5

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

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

这个BackgroundWorker类在这里非常有用。

于 2010-08-05T16:04:58.200 回答
4

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

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

由于这是由 CLR 管理的,因此没有真正的需要,还是有任何具体原因?

肯定是有需要的。线程不是免费的——它必须由开发人员添加。这不是很常见的主要原因,尤其是在开源代码中,实际上更多的是一个困难问题。即使使用 .NET 4,正确设计算法以以可扩展、安全的方式进行线程处理也很困难。

于 2010-08-05T16:07:42.560 回答
3

这完全取决于应用程序。

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

根据我的经验,Web 服务和 Web 应用程序不太可能创建自己的线程。您更有可能有效地将每个请求视为具有单独的线程(即使 ASP.NET 在内部移动它)并同步执行所有操作。当然,有些Web 应用程序要么异步执行,要么出于其他原因启动线程——但我想说这比在客户端应用程序中出现的频率要低。

于 2010-08-05T16:07:09.877 回答
2

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

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

总体而言,如果您正在考虑在 .NET 中构建并发应用程序,那么您应该自己研究一下 Parallel Extensions。我还认为,鉴于这是 Microsoft 的一项相当初期的努力,您应该非常清楚哪些对您有用,哪些对您无效,而与您认为自己的并发技能水平无关。微软肯定在倾听,但我认为使用并行扩展的人并不多。我昨天在 VSLive Redmond 观看了有关此主题的会议,并继续对致力于此的团队印象深刻。

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

于 2010-08-05T17:29:40.773 回答
1

我见过的大多数线程的实际使用只是为了避免阻塞——UI、网络、数据库调用等。

您可能会看到它被用作方法对、BeginXXX调用、调用。EndXXXdelegate.BeginInvokeControl.Invoke

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

我认为可以公平地说,您会发现很多股票和交易应用程序(数据呈现)在很大程度上不需要大规模并行化,它们也不总是能够被设计成适合它的架构。我看到的例子都是非常具体的问题。这可能归因于为什么您没有看到任何值得注意的实现。

于 2010-08-05T16:07:43.123 回答
1

正如其他人在这里提到的那样,是否使用显式线程实现的问题通常是设计考虑因素。尝试将并发作为事后的想法通常需要进行大量的彻底和全面的更改。

请记住,简单地将线程投入应用程序并不会从本质上提高性能或速度,因为管理每个线程是有成本的,而且可能还有一些内存开销(更不用说,调试它可能很有趣)。

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

例如,您可以查看Microsoft Robotics Studio(据我所知,现在有一个免费版本) - 它带有Concurrency and Coordination Runtime的可再分发(我找不到它作为独立下载),有微软第 9 频道对此进行了一些报道。

正如其他人所提到的,Parallel Extensions 团队(博客在此处)在线程安全和并行执行方面做了一些出色的工作,您可以在MSDN 代码站点上找到一些示例/示例。

于 2010-08-05T17:51:56.260 回答
0

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

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

于 2010-08-05T16:10:00.140 回答
0

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

事实上,此时我正在检查一个将 200MB 文件上传到 200 个不同 FTP 位置的应用程序。我们使用SmartThreadPool并并行运行大约 50 次上传,这使得整个批次可以在一小时内完成(而不是超过 50 小时,所有上传都是连续发生的 - 所以在我们的使用中,我们发现在时间)。

于 2010-08-05T16:14:13.060 回答
0

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

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

于 2010-08-05T16:21:28.857 回答
0

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

案例 1 - 对于必须实现极高运行可靠性水平的系统,可以在投票架构中使用使用三种不同机制的三个完全独立的子系统 - 在每个投票者之间产生 3 个线程/进程,等待他们结束/死亡/被杀死,然后继续 IFF 他们都说同样的话 - 例子 - 复杂的航空电子系统

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

于 2010-08-05T19:21:46.230 回答