【问题标题】:C# Threading in real-world apps实际应用中的 C# 线程
【发布时间】:2010-08-05 16:03:26
【问题描述】:

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

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

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

【问题讨论】:

    标签: c# multithreading codeplex


    【解决方案1】:

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

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

    BackgroundWorker 类在这里非常有用。

    【讨论】:

    • 没错,我在进度条或繁重的计算中经常使用线程,这样 GUI 就不会冻结和无响应。
    【解决方案2】:

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

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

    由于这由 CLR 管理而没有真正的需要,还是有任何特定原因?

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

    【讨论】:

    • +1 线程绝对是设计的一部分!!!!毫无疑问! @Reed那么这是否意味着由于困难而可有可无?我感到困惑的原因甚至是在非开源应用程序中。避免了关键任务线程。
    • @Shankar:我个人认为它根本不是“可有可无的”——现代开发确实应该在适当的时候使用线程,并且它非常适合(部分)几乎每个客户端应用。话虽如此,它经常因为困难而被忽略,即使它不应该是......线程确实增加了应用程序的维护成本,但它确实是可用性所必需的。
    【解决方案3】:

    这完全取决于应用程序。

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

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

    【讨论】:

    • 此类广泛使用的客户端应用程序的任何示例。来自 Codeplex 还是 Code?​​span>
    • @GilliVilla:不是我知道的副手。但是寻找客户端应用程序,它们可能会在某处使用线程......
    • 跟进:客户端应用程序也可以使用响应式扩展(即将完成)。此外,当 Jon 谈到 Web 应用程序将“每个请求视为 (sic:has) 有一个单独的线程”时,这也确实包括异步页面。
    【解决方案4】:

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

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

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

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

    【讨论】:

      【解决方案5】:

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

      您可能会将其用作 BeginXXXEndXXX 方法对、delegate.BeginInvoke 调用、Control.Invoke 调用。

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

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

      【讨论】:

        【解决方案6】:

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

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

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

        例如,您可以查看Microsoft Robotics Studio(据我所知现在有一个free version)-它带有@987654323 的可再分发(我找不到它作为独立下载) @,在微软的Channel 9 上有一些报道。

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

        【讨论】:

          【解决方案7】:

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

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

          【讨论】:

            【解决方案8】:

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

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

            【讨论】:

              【解决方案9】:

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

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

              【讨论】:

                【解决方案10】:

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

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

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

                【讨论】:

                  猜你喜欢
                  • 2017-06-26
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-07-25
                  • 1970-01-01
                  • 2011-01-05
                  • 2015-10-13
                  • 1970-01-01
                  相关资源
                  最近更新 更多