很难在.NET中找到有关工作线程和I / O线程的详细但简单的描述
关于这个主题我有什么好看的(但可能在技术上不准确):
不清楚的是:
答案 0 :(得分:59)
.net / CLR中的术语“工作线程”通常仅指代主线程以外的任何线程,它代表生成线程的应用程序执行某些“工作”。 “工作”可能意味着什么,包括等待一些I / O完成。 ThreadPool保留了工作线程的缓存,因为线程的创建成本很高。
.net / CLR中的术语“I / O线程”是指ThreadPool保留的线程,用于从“重叠”的win32调用(也称为“完成端口I / O”)调度NativeOverlapped回调。 CLR维护自己的I / O完成端口,并且可以绑定任何句柄(通过ThreadPool.BindHandle API)。示例:http://blogs.msdn.com/junfeng/archive/2008/12/01/threadpool-bindhandle.aspx。许多.net API在内部使用这种机制来接收NativeOverlapped回调,尽管典型的.net开发人员不会直接使用它。
'工作线程'和'I / O线程'之间确实没有技术差异 - 它们都只是普通线程。但是CLR ThreadPool保留了每个池的独立池,以避免工作线程的高需求耗尽可用于调度本机I / O回调的所有线程,从而可能导致死锁。 (想象一下使用所有250个工作线程的应用程序,其中每个线程都在等待一些I / O完成)。
开发人员在处理I / O回调时需要注意,以确保I / O线程返回到ThreadPool - 也就是说,I / O回调代码应该完成所需的最少工作服务回调,然后将线程的控制权返回给CLR线程池。如果需要更多工作,则应该在工作线程上安排该工作。否则,应用程序可能会“劫持”CLR的保留I / O完成线程池,以用作正常的工作线程,从而导致上述死锁情况。
进一步阅读的一些很好的参考: win32 I / O完成端口:http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx 托管线程池:http://msdn.microsoft.com/en-us/library/0ka9477y.aspx BindHandle的例子:http://blogs.msdn.com/junfeng/archive/2008/12/01/threadpool-bindhandle.aspx
答案 1 :(得分:7)
我将首先介绍NT中程序如何使用异步I / O.
您可能熟悉Win32 API函数 ReadFile (作为示例),它是Native API函数 NtReadFile 的包装器。此函数允许您使用异步I / O执行两项操作:
然而,当I / O操作完成时,会有第三种通知方式。您可以创建 I / O完成端口对象并将文件句柄与其关联。只要对与I / O完成端口关联的文件完成操作,操作结果(如I / O状态)就会排队到I / O完成端口。然后,您可以设置专用线程以从队列中删除结果,并执行适当的任务,如调用回调函数。这基本上就是“I / O工作线程”。
正常的“工人线程”非常相似;它不是从队列中删除I / O结果,而是从队列中删除工作项。您可以对工作项( QueueUserWorkItem )进行排队,并让工作线程执行它们。这可以防止您每次要异步执行任务时都必须生成一个线程。
答案 2 :(得分:3)
简单地说,一个工作线程意味着执行一段短时间的工作,并在完成它时自行删除。回调可用于通知父进程它已完成或传回数据。
I / O线程将持续执行相同的操作或一系列操作,直到父进程停止。之所以这么称呼,是因为通常设备驱动程序会持续监视设备端口。 I / O线程通常会在希望与其他线程通信时创建事件。
所有进程都以线程运行。 您的应用程序作为线程运行。 任何线程都可能产生工作线程或I / O线程(就像你调用它们一样)。
性能与使用的线程数量或类型之间始终存在良好的平衡。进程处理的回调或事件过多会严重降低其性能,因为它处理主进程循环时会有多次中断。
工作线程的示例是在用户交互之后将数据添加到数据库中,或者执行长数学计算或将数据写入文件。通过使用工作线程释放主应用程序,这对于GUI来说非常有用,因为它在执行任务时不会冻结。
答案 3 :(得分:0)
比我更有技巧的人会跳到这里帮忙。
工作线程有很多状态,它们由处理器等安排,你可以控制它们所做的一切。
IO完成端口由操作系统提供,用于涉及很少共享状态的非常特定的任务,因此使用起来更快。 .Net中的一个很好的例子是WCF框架。对WCF服务的每次“调用”实际上都是由IO完成端口执行的,因为它们是最快启动的,操作系统会为您提供服务。