当一个线程同步执行一个可能已经被等待的异步方法时(例如一个持久的网络操作),该线程不能被重用,但是该线程是否也会因空闲运行而浪费CPU资源?或者.NET /操作系统会知道一个线程当前正在等待,甚至不会将其分配给CPU吗?
string result = DownloadStringAsync().Result // will I be wasting CPU resources as well or just blocking the current thread?
字符串
这是不言而喻的,但不要这样编写代码。
2条答案
按热度按时间1mrurvl11#
不会。阻塞不会浪费CPU时间,至少不会浪费大量时间。它确实“浪费”了一些内存,因为每个线程都有一些内存,并且线程在阻塞时不能用于其他任何事情。
阻塞一个线程将该线程标记为未准备好执行,并且调度程序将调度其他线程执行,直到被阻塞的线程被解除阻塞。
有一个“自旋锁”的概念,本质上就是一个检查共享变量的循环。这确实会浪费CPU时间,但会导致更低的延迟,因为线程不会丢失其时隙。如果由于CPU被等待线程占用而无法调度持有锁的线程运行,这也可能导致问题。
使用
Monitor
(如lock
)的同步使用混合方案,其中它将首先在一定数量的周期内使用自旋锁,如果监视器在此期间不可用,它将暂停线程。我不确定.Result
是否使用了监视器或其他同步机制,但是您可能不应该担心这两种情况。如果你写了一个UI程序,你应该担心死锁。因为在UI线程上使用
.Result
,需要UI线程完成的任务将导致死锁。任务是否需要UI线程来完成并不总是显而易见的。另一个需要关注的潜在问题是线程池耗尽,在这种情况下,所有或大多数线程都被阻塞,因此可供运行的任务无法获得可供运行的线程。线程池将创建新的线程以避免完全锁定,但这是故意缓慢的。
y1aodyip2#
当线程同步执行异步方法时。。
请允许我纠正你的术语。异步方法通常为don't run on threads。在大多数情况下,它们使用CPU以外的硬件,如网卡或磁盘驱动器,其中“线程”的概念不适用。当您使用
.Wait()
、.Result
或.GetAwaiter().GetResult()
等待Task
时,您指示阻塞当前线程,直到任务完成。线程的阻塞不会以任何方式帮助异步操作。这是一个寄生在异步操作上的事件,您出于自己的原因决定附加它。内部发生的事情(源代码)是ManualResetEventSlim
被示例化,它被挂接为任务继续的信号,并且它的方法Wait
被调用。ManualResetEventSlim.Wait
方法阻塞当前线程,直到组件被另一个线程Set
。一个被阻塞的线程doesn't consume CPU resources。的数据