我对IOCP有所了解,但我对APM有些困惑。
static FileStream fs;
static void Main(string[] args)
{
fs = new FileStream(@"c:\bigfile.txt", FileMode.Open);
var buffer = new byte[10000000];
IAsyncResult asyncResult = fs.BeginRead(buffer, 0, 10000000, OnCompletedRead, null);
Console.WriteLine("async...");
int bytesRead = fs.EndRead(asyncResult);
Console.WriteLine("async... over");
}
static void OnCompletedRead(IAsyncResult ar)
{
Console.WriteLine("finished");
}
我想知道,IO线程异步执行的读取操作是什么?还是线程池中的工作线程?
回调函数OnCompletedRead
,它是否也由CLR线程池中的IO线程执行?
这两个线程是同一个吗?如果没有,则生成两个线程,一个执行读取操作,另一个执行回调。
如果你没有在BeginRead中使用AsyncCallback参数,那么只有一个线程在你的程序中运行代码。这使用IO完成端口通过在IO线程池中的线程上运行少量代码来完成IO完成时的信号,以更新操作的状态。当您调用EndRead时,它将阻止当前线程,直到IO操作完成。它是异步的,当你开始读取操作时,当前线程除了等待IO硬件执行读取操作之外不需要做任何事情,所以你可以在此期间做其他事情,然后决定你想什么时候停止并等待IO完成。
如果确实传入了AsyncCallback,那么当IO操作完成时,它将在IO线程池线程上执行少量代码,这将触发您的回调方法在.NET线程池的线程上执行。
通常,mclaassen对IO绑定工作,IOCP和APM的性质是正确的。当BeginRead
执行时,它会一直异步到内核模式。但是,你的例子中有一个警告,他在答案中没有提到。
在您的示例中,您使用FileStream
类。需要注意的一件重要事情是,如果你不使用接受FileStream
布尔值的useAsync
重载,当你调用BeginWrite
/ EndWrite
操作时,它将在新的ThreadPool
线程上排队工作。
这是适当的过载:
public FileStream(
string path,
FileMode mode,
FileAccess access,
FileShare share,
int bufferSize,
bool useAsync
)
来自MSDN:
useAsync:
键入:System.Boolean
指定是使用异步I / O还是同步I / O.但请注意,底层操作系统可能不支持异步I / O,因此在指定true时,可能会根据平台同步打开句柄。异步打开时,BeginRead和BeginWrite方法在大型读取或写入时执行得更好,但对于小型读取或写入,它们可能要慢得多。如果应用程序旨在利用异步I / O,请将useAsync参数设置为true。正确使用异步I / O可以将应用程序的速度提高10倍,但在不重新设计异步I / O应用程序的情况下使用它可以将性能降低10倍。
您必须确保实现APM模式的每个特定方法真正使用真正的异步工作。