Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 切换到线程与睡眠(1)_C#_.net_Multithreading_Winapi_Sleep - Fatal编程技术网

C# 切换到线程与睡眠(1)

C# 切换到线程与睡眠(1),c#,.net,multithreading,winapi,sleep,C#,.net,Multithreading,Winapi,Sleep,我想知道调用Thread.Sleep(1)和调用SwitchToThread(如果我们忽略了BCL当前没有公开它)之间的实际区别是什么 乔·达菲在书中提到: “kernel32!SwitchToThread API没有出现睡眠(0)和睡眠(1)所出现的问题。”(关于调度程序的行为) 为什么睡眠的行为与SwitchToThread不完全一样?为什么会存在这种差异,它有什么好处?(如果有的话)有两个区别。第一个在MSDN文档中提到: 执行的产量仅限于调用线程的处理器。操作系统不会将执行切换到另一个处

我想知道调用Thread.Sleep(1)和调用SwitchToThread(如果我们忽略了BCL当前没有公开它)之间的实际区别是什么

乔·达菲在书中提到:

“kernel32!SwitchToThread API没有出现睡眠(0)和睡眠(1)所出现的问题。”(关于调度程序的行为)


为什么睡眠的行为与SwitchToThread不完全一样?为什么会存在这种差异,它有什么好处?(如果有的话)

有两个区别。第一个在MSDN文档中提到:

执行的产量仅限于调用线程的处理器。操作系统不会将执行切换到另一个处理器,即使该处理器空闲或正在运行优先级较低的线程

睡眠(0)也将允许其他处理器上的线程运行

SwitchToThread也只允许使用单线程调度上下文。另一方面,睡眠有多种等待的条件。这些文件详细说明了这一点:

* An I/O completion callback function is called
* An asynchronous procedure call (APC) is queued to the thread.
* The time-out interval elapses
这将产生多个线程

通常,Sleep(0)更有可能产生时间片,并且始终会让位于操作系统,即使没有其他线程等待。这就是为什么在循环中添加睡眠(0)在许多情况下会使处理器使用率从100%(每个核心)提高到接近0%。除非另一个线程正在等待时间片,否则SwitchToThread将不会运行。

SwitchToThread()是睡眠(0)的“更智能”版本。它没有很好的文档记录,但据我所知,它的工作方式如下:

  • 当有其他线程处于
    ready
    状态时(即,要运行的线程比可用的逻辑处理器多),并且这些线程的优先级与调用SwitchToThread()的线程相同或更高,其行为方式与Sleep(0)相同,即将逻辑处理器割让给其中一个线程,代价高昂的上下文切换
  • ready
    状态中有优先级较低的线程时,它只是退出,即调用SwitchToThread()的线程继续执行,而不需要任何上下文切换或3到0的转换(它不会离开用户模式)——这与睡眠(0)的方式相反总是将控制权让给最低优先级线程的行为
  • 当没有线程处于
    ready
    状态时,SwitchToThread()也会像Sleep(0)一样退出-因此,如果在循环中执行此操作,您只会得到当前逻辑处理器的100%负载,即耗电
  • 睡眠(1)与睡眠(0)相同,但向下延迟1毫秒。这1毫秒的延迟释放了逻辑处理器,并且不会消耗任何电源。相反,SwitchToThread从不经历任何延迟

    所以最好将SwitchToThread与Sleep(0)进行比较,而不是与Sleep(1)进行比较,因为Sleep(1)与Sleep(0)+1毫秒的延迟相同

    在这个问题上,我从“英特尔64和IA-32体系结构优化参考手册”和“英特尔64和IA-32体系结构软件开发人员手册”中借用了一些想法,如果等待时间很短,它们倾向于调用一些
    pause
    CPU指令(也可用作内部函数),而不是SwitchToThread()或Sleep(0)。请注意,SwitchToThread()或Sleep(0)几乎是即时的,而Sleep(1)至少持续一毫秒

    还应考虑以下因素:

    • 对Sleep()或SwitchToThread()的每次调用都会经历昂贵的上下文切换成本,这可能需要10000多个周期
    • 它还承受环3到环0转换的成本,这可能是1000多个周期
    • 如果没有线程处于
      ready
      状态,则SwitchToThread()或Sleep(0)可能没有用处,但是Sleep(1)至少会等待一毫秒,而不管是否有其他线程处于“ready”状态

    如果您的等待循环很短,请首先考虑执行一些<代码>暂停> /代码> CPU指令。通过在SwitchToThread()或Sleep()调用之前使用一些

    pause
    CPU指令减慢“旋转等待”,多线程软件获得:

    • 通过帮助等待任务更容易地从繁忙的等待中获取资源来提高性能
    • 通过在旋转时使用更少的管道部件来节省电力
    • 消除由SwitchToThread()或Sleep(0)或Sleep(1)调用的开销引起的绝大多数不必要执行的指令
    但是,如果您要调用Sleep(1),它至少运行一毫秒,这在CPU周期方面非常长,那么您预计等待周期将非常长,因此在这种情况下,
    pause
    指令将是无效的

    当等待循环预计会持续很长时间时,最好通过调用一个操作系统同步API函数(如Windows操作系统上的WaitForSingleObject)而不是SwitchToThread()或Sleep(0)或Sleep(1))让位于操作系统,因为它们在长时间等待时非常浪费时间。此外,Sleep(1)非常慢,操作系统同步功能(如WaitForSingleObject或EnterCriticalSection)的响应速度会更快,而且对资源更友好

    我的结论是:最好不要使用Sleep(0)、Sleep(1)或SwitchToThread()。不惜一切代价避免“旋转等待”循环。使用高级同步功能,如WaitForMultipleObjects()、SetEvent()等,它们在性能、效率和节能方面都是最好的。尽管它们也会受到昂贵的上下文切换和从环3到环0的转换的影响,但与使用Sleep()或SwitchToThread()的“spin wait”循环相比,这些开销并不频繁,也非常合理

    在支持HT技术的处理器上,自旋等待循环可能会占用大量端口