【问题标题】:Multi-core processor pegged even when all threads are just sleeping即使所有线程都处于休眠状态,多核处理器也会保持不变
【发布时间】:2010-03-03 00:48:30
【问题描述】:

我正在模拟 Windows 服务中的一些线程,我的每个线程的 Thread.Start 例程都直接指向以下内容:

Private WithEvents CheckForOrdersTimer As System.Threading.Timer

Private Sub timerCheckForContracts_Tick(ByVal stateInfo As Object)
    ' Ticks every 5 seconds, then spawns threads until we're at our max
    Do

        If ThreadCollection.Count < MaxThreads Then

            Dim t As New Threading.Thread(AddressOf SomeThreadingCode()
            ThreadCollection.Add(t)
            t.Start()

        End If
    Loop

End Sub


Private Sub SomeThreadingCode()
    Do
        Thread.Sleep(1000)
        If Me.ThreadsShouldContinue = False Then  ' Global thread-stopper
            Exit Sub
        End If
        If (New Random).NextDouble > 0.8 Then  ' On average, wait 5 seconds
            Exit Do
        End If

    Loop

    ' Remove this thread from the main collection
    ThreadCollection.Remove(Thread.CurrentThread)

End Sub

非常简单 - 线程甚至还没有做任何事情,但是同时运行两个以上的线程,我的处理器(Core 2 Duo 2.4 w/4GB)被固定,Windows 变得非常缓慢。根据我所读到的,Thread.Sleep 在等待时根本不应该消耗任何资源,但它也可能在一个紧凑的时序循环中运行。

谁能给我解释一下这里发生了什么?

编辑:根据请求,我已经扩展了我正在使用的代码量。在生成每个线程之前,我最初是在做一些数据库工作,但我已经删除了它,并且仅使用此处的代码(当然还有 Windows 服务的 OnStart 方法)仍然会发生处理器最大化。

【问题讨论】:

  • 线程代码看起来不错。这个函数调用了什么?
  • 您是否在用力旋转产生其他两个的线程?
  • @Justin Ethier - 我已经更新了代码以包含生成代码。
  • @SB - 我不这么认为 - 我已经更新了代码。是否有工具可以用来查看每个线程上的资源使用情况,以便知道哪个线程在旋转?

标签: .net vb.net multithreading


【解决方案1】:

timerCheckForContracts_Tick 正在运行一个无限循环,并且永远不会进入睡眠状态等。即使您每 5 秒“滴答”一次,循环中也没有代码可以防止它消耗 CPU 周期,永远检查:

    If ThreadCollection.Count < MaxThreads Then

【讨论】:

  • 该死,打败我 :-) 这就是答案!
  • 哇 - 我不敢相信我错过了。我打算添加一些退出逻辑来防止这种情况,但显然我忘记了。我已经将循环切换为“直到计数> = MaxThreads”,它使我的处理器利用率几乎为零。谢谢 - +15 给你。
【解决方案2】:

好吧,您的代码中有 4 条语句,其中 3 条是错误的。 ThreadsShouldContinue 无法正常工作,因为 VB.NET 没有“volatile”关键字。 Random 语句不能很好地工作,因为您每次都创建 Random 类的新实例,从而阻止它真正随机。而且Remove()方法调用不能很好,因为你没有使用SyncLock语句。

Sleep() 调用是唯一没有问题的语句。这能说明问题吗?可能不是。使用 Debug + Break All 查看线程在做什么。

【讨论】:

  • 我可以稍微长一点的结束时间,所以似乎不需要 VOLATILE(或 VB.NET 等效代码),只建议确保选择对变量的更改立即起来。我已经将“随机”移动到我通过函数调用的单个实例,使用同步锁定,所以我想我现在没问题。第三,由于线程只会从 List(of Thread) 中删除自己,那么 SyncLock 是否仍然需要?无论如何我都会添加它,我想。
  • 需要可变语义,否则 JIT 优化器可以将变量存储在寄存器中。它永远循环。请改用 ManualResetEvent。多个线程对列表进行变异是安全的,列表可能会损坏。 SyncLock 非常需要。
  • 感谢您的澄清 - 我将在一些 SyncLock 中包装我的列表管理。我想从不同线程同时从列表中添加删除的想法应该引起一些关注。
【解决方案3】:

这里没有足够的帮助。线程是如何创建的?主线程上发生了什么?控制台或 WinForm 应用程序?如果您每五秒钟创建和销毁一次线程,那将占用资源。研究 Threadpool 以了解缓存线程的方法,这样您就可以避免创建和销毁它们的成本。

【讨论】:

    【解决方案4】:

    这段代码不应该循环,睡眠看起来不错。睡眠不使用 CPU。你的其他线程正在某个地方旋转。

    另外,您应该使用事件来发出终止信号,而不是在睡眠/布尔测试中循环

    默默地忽略所有异常并不会让事情更容易调试

    【讨论】:

    • 我最初认为在 Service OnStop 期间停止线程的唯一方法是全部中止它们 - 我将在 Catch 块中处理清理工作。如果有一种方法可以使用事件来处理停止通知,我更喜欢那个 - 你能指出一个例子吗?我在网上看到的代码使用“If Not Closing Then”检查,类似于我在这里所做的。
    猜你喜欢
    • 2017-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 2012-09-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 2021-04-05
    相关资源
    最近更新 更多