我对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线程执行?
这两个线程是否相同?如果没有,则生成两个线程,一个执行读取操作,另一个执行回调。
答案 0 :(得分:5)
如果你没有在BeginRead中使用AsyncCallback参数,那么只有一个线程在你的程序中运行代码。这使用IO完成端口通过在IO线程池中的线程上运行少量代码来完成IO完成时的信号,以更新操作的状态。当您调用EndRead时,它将阻止当前线程,直到IO操作完成。它是异步的,当你开始读取操作时,当前线程除了等待IO硬件执行读取操作之外不需要做任何事情,所以你可以在此期间做其他事情,然后决定你想什么时候停止并等待IO完成。
如果确实传入了AsyncCallback,那么当IO操作完成时,它将在IO线程池线程上执行少量代码,这将触发您在.NET线程池的线程上执行的回调方法。
答案 1 :(得分:2)
通常,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模式的每个特定方法都真正使用真正的异步工作。