【问题标题】:Why C# threads goes idle during the execution?为什么 C# 线程在执行期间会空闲?
【发布时间】:2013-05-07 17:32:07
【问题描述】:

我有一个调度程序,它在 ASP.NET 站点的应用程序启动时作为后台线程运行。用户可以启动插入到数据库表中的各种任务(警报电子邮件/文件生成等)。调度程序将从数据库中选择任务并将项目推送到堆栈中。调度程序还有一个线程池,运行 10 个后台线程,这些线程将从堆栈中弹出任务项并执行它。

这在一台网络服务器上运行良好,但在另一台网络服务器上表现异常。即使堆栈中有项目,线程也会无缘无故地空闲 6-12 秒,并且什么也不做。

  • 在堆栈对象上使用 lock() 使 Push & Pop 线程安全
  • 尝试 Thread.Yield() 让 cpu 让出以执行其他线程,但仍然会减慢执行速度并保持空闲状态
  • 尝试 Thread.Sleep(0) 让 cpu 让出以执行其他线程,但仍然会减慢执行速度并保持空闲状态
  • 记录所有方法的进入和退出,以检查执行过程中是否出现问题,但没有运气

我的问题:

  1. .net 中线程的执行是否具有不确定性?
  2. 是否需要指定 Thread.Yield() 或 Thread.Sleep(0) 给 cpu 呼吸时间?
  3. 为什么它在具有相同配置的盒子上表现不同?是否有任何特定于机器/环境的因素会影响线程的执行?

2013 年 5 月 8 日更新

农场中有两个盒子,硬件配置相同,软件配置相同,Windows 2008 64bit / IIS7。两个网络服务器只有一个站点,每个站点都具有相同的构建。两个站点的应用程序池在 Framework V4.0 上以集成模式运行。这是一个遗留代码,自过去两年以来没有机会。

我们尝试了几次迭代,在所有情况下,webserver1 都可以正常执行,并像之前一样快速完成后台工作。 但是 webserver2 有很大的延迟并且性能很差。

我们尝试了广泛的日志记录,捕获所有方法的条目/退出。场景是这样的,所有线程正常工作 2 秒,然后空闲 6-12 秒,再次变为活动并执行接下来的 2 秒,然后再次空闲。这种行为一直持续到任务完成。没有异常,没有应用程序终止,应用程序池/iis日志中没有错误。

有什么想法吗?

【问题讨论】:

  • 1.是的。 2. 没有。 3. 你可能有一个错误/竞争条件,只有一种配置能够带来;如果不了解更多关于代码的信息,这很难确定。
  • 因为这两种方法都在告诉线程在一段时间内什么都不做,明显的结果是吞吐量降低。
  • 您在问一个只有调试器才能可靠回答的问题。调试 + 全部中断,调试 + Windows + 线程。查看他们的调用堆栈,看看他们在做什么。
  • @eka 当然,很多。它将确定哪些线程在什么时间被安排在哪些内核上,它们运行多长时间,它们运行的​​速度,有多少能够同时运行,花多少时间进行生产性工作与上下文切换,然后有是关于如何基于缓存等访问共享内存的各种问题。这只是初学者。
  • @eka 正在运行的任务是否有可能争用共享资源? (也许其中一个任务是长时间运行的并且持有共享资源的锁)

标签: c# .net multithreading parallel-processing clr


【解决方案1】:

您的线程反复尝试获取可能导致争用的锁。但不应该是 6-12 秒 - 只有调试器才能提供的答案。

您可以使用 AutoResetEvent 并在工作线程中等待它 - 以及 Set 将项目推送到堆栈时的事件。

【讨论】:

  • nop,我不这么认为,我们记录了方法的进入和退出,并且 lock 语句在方法调用中。他甚至没有采用这种方法。如果只有两个线程,我也可以使用自动重置事件来相互通知。就我而言,有多个线程 (10) 正在监视堆栈。我无法调用 reset 来通知特定线程
  • 对不起,没有理解“他甚至没有使用方法”的意思。
  • 如果您使用发布构建二进制文件,您的调试写入语句将不会被打印。请改用Trace。所有 10 个线程都可以等待一个 AutoResetEvent。当您将一项推送到堆栈时,调用Set。其中一个等待线程将被释放并处理项目。无需致电Reset
  • 基于问题本身的一些 cmets 和 @sgorozco 的一条评论 - 如果 Mock 代码运行良好,那么我们不可能解决您的问题。你必须透露更多细节。线程冻结的一种可能性是垃圾收集。检查是否在启动时创建了太多对象,从而无意中引发了 GC。对你来说最好的解决方案是如果你有 $$$ 然后通过探查器运行你的代码。或者,您也可以在看到延迟并检查 heapstats 时对进程进行挂起转储。
  • 好的 - 看起来我们在这个讨论中缺少一些基本的东西。由于您的系统是生产机器 - 您可能在那里没有 VS。当您看到 2-3 分钟的延迟时,您可以使用 VS 独立分析器并对应用程序池进程进行 CPU 采样。 msdn.microsoft.com/en-us/library/bb385771.aspx
【解决方案2】:

好吧,我们终于解决了这个问题。

其中一个网络服务器的 cpu 核心达到 100% 并且再也没有回来。而其他核心为 0-5%。

我们针对正常 - 中等 - 重载进行了负载测试。在生成正常到中等负载的同时,服务器运行良好,与所有其他 cpu 内核正确共享进程执行。但是当我们产生重负载时,情况发生了变化,服务器难以在内核之间分配负载,线程空闲 6-7 秒。我们假设由于一个 cpu 内核的故障,它处理了一些模糊逻辑来在内核之间分配进程。

经过进一步调查,我们发现 Windows NT 内核导致了这个问题,可能是由于损坏或驱动程序相关问题。

【讨论】:

    猜你喜欢
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 2012-12-28
    • 1970-01-01
    • 2012-08-26
    • 2021-05-08
    相关资源
    最近更新 更多