问题 在线程中“浪费时间”的CPU效率最高的方法是什么?


我有许多线程(100),每次执行几秒钟。当它们执行时,它们花费大量时间等待来自另一个系统(串行设备)的响应。我注意到一次执行100个线程可能是资源占用,所以我实际上限制了任何时候都可以启动的线程数。

虽然在线程中等待外部事件必须有好的和坏的方法,但我想到了这一点。这种方法是CPU密集型的吗?:

send command ;
repeat
until response arrived ;
process response ;    

这种方法是否会提高效率?:

send command ;
repeat
    Sleep (20) ;
until response arrived ;
process response ;  

* 附加信息 *

环境是x86 Windows XP。线程代码是与串行设备进行的一系列长时间的交互,但通常,它包括将字符写入COM端口(使用AsyncFree串行库)并等待通过驻留在传入的字符缓冲区和他们到达时处理它们。我想这个串行库会让设备读写。线程中的时间可以长达一分钟,也可以短至几秒钟,但大部分时间都花在等待字符离开端口或等待响应字符(波特率很慢),因此我的问题是关于线程在等待时表现的最佳方式。目前我在打电话 Sleep 在一个循环中等待 CharactersInBuffer 变为非零,在到达时处理每个字符,并在我有完整的响应时退出该字符。所以代码看起来更像(忽略超时处理等):

send command ;
Packet = '' ;
repeat

    repeat
        Sleep (20) ;
    until response character arrived ;
    build Packet

until complete packet arrived
process response ;  

1445
2017-11-01 19:19


起源

请发布可能相关的操作系统。 - Chris O
这取决于循环正在做什么。你能提供代码吗? - Marcus Adams
如果你没有看到100%的CPU利用率,那么听起来你没有问题。没有看到真正的代码,很难说更多。 until response arrived 是关键。这究竟是做什么的?这是阻塞电话吗? - David Heffernan
@rossmcm:应该有一种方法让线程等待来自操作系统的通知,即响应可用而不是轮询它。 - afrazier
@rossmcm如果你的线程已经阻塞,你可能无所事事。 - David Heffernan


答案:


如果线程真正等待WaitForSingleObject之类的东西,它不使用处理器时间,那么超时,就没有理由在线程中使用sleep来延迟。

您的用户没有等待线程响应,它没有使用处理器时间,并且其他线程不会被阻止,因此没有理由让线程进入休眠状态。

正如David Heffernan在评论中指出的那样,如果它现在没有使用100%的CPU,那么就没有问题了。

如果你是单线程的话,你可以使用sleep(),你不得不偶尔在等待串口响应用户之间做出响应。

此外,线程休眠不会使其更有效。它只会为其他线程产生处理器周期。

看一眼 sleep(0) 作为CPU在线程中“浪费时间”的有效方式。


7
2017-11-01 19:41



Also, having a thread sleep would not make it more efficient. It would simply yield processor cycles to other threads.   这不是重点吗?如果我让我的线程睡眠到20毫秒并且处理到其他线程,那么这不会使更多的CPU可用于其他线程/其他进程吗?如果我有10000个线程并且它们刚刚进入睡眠(10000)状态,那么它们的CPU使用率是多少? - rossmcm
@rossmom,如果我在车队,停下我的卡车让别人通过不会提高效率。需要完成相同数量的工作。它更有礼貌。如果我在没有人通过时停下我的卡车,我就是在浪费时间。如果10000个线程处于休眠状态,从技术上讲,它们使用的是0 CPU使用率,尽管操作系统(调度程序)线程需要做很多工作,如果RAM耗尽,你肯定会放慢速度。使用sleep(0)将尽快完成所有事情,同时仍然保持礼貌。睡眠(0)比睡眠(200)更有效,因为时间也是资源。 - Marcus Adams
好的,所以我现在明白Sleep(0)有效地说“继续前进,没有什么可做的”,所以如果我坚持我当前的架构,限制可以开始十的线程数,并取代我的睡眠(20)通过Sleep(0),我会遇到低延迟和低CPU使用率的情况? - rossmcm
@rossmcm Sleep(0) 只有在准备好运行线程等待时才会产生。否则它是一个小鸟。 - David Heffernan
@rossmcm,睡眠(0)而不是睡眠(20),你会有低延迟,但你可以保证更高的CPU使用率,同时还有工作要做。 CPU使用率也不错。如果没有其他人在使用CPU,为什么不呢?睡眠(0)将使计算机对其他进程保持响应,这有助于保持UI响应,并允许用户在程序运行时继续观看他们的电影或上网。如果你想故意让用户等待Sleep(20),这样他们就不会看到CPU峰值,这是你的特权。我更喜欢他们认为他们的计算机速度慢而不是我的程序。 - Marcus Adams


防止线程使用CPU时间的最有效方法是将其置于“等待模式”。

我根本不使用delphi,但似乎基本原理就在那里。看到 “第11章同步器和事件” 更具体地说 “使用信号量的事件模拟”

如果您想在不使用CPU的情况下等待,请使用 WaitForEvent

检查事件的信号状态。如果它指示事件已发出信号,则发信号通知内部信号量,并减少信号量上阻塞的线程数。然后递增阻塞线程的计数,并对内部信号量执行等待。

如果这与I / O相关,那么事情就会有所不同。如果它是一个套接字,那么它可能已经被阻塞,如果它是异步I / O,那么你可以使用一个信号量和 WaitForEvent 等等。

在.NET中有 Monitor.WaitMonitor.SignalManualResetEventCountDownLatch等等,但我不知道delphi中的等价物是什么。


2
2017-11-01 19:44





我不能说AsyncFree的功能,但一般来说,Windows中的COM端口编程支持重叠I / O,因此您可以通过使用以下方式有效地等待数据到达时的通知 WaitCommEvent() 功能与其中之一 WaitFor...() 一系列功能,如 WaitForSingleObject()。线程可以进入休眠状态,直到通知发出,此时它“唤醒”从端口读取,直到没有任何进一步的读取,然后它可以回到睡眠直到下一次通知。


2
2017-11-02 01:41