在c#中,当我调用BeginXXX时,有两个线程

本文关键字:两个 线程 BeginXXX 调用 | 更新日期: 2023-09-27 18:16:32

我对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线程执行?

这两个线程是同一个线程吗?如果没有,则生成两个线程,一个执行读取操作,另一个执行回调。

在c#中,当我调用BeginXXX时,有两个线程

如果你不使用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:

类型:系统。布尔

是否使用异步I/O或同步I/O。但是,请注意底层操作系统可能不支持异步I/O,所以当指定true时,根据平台的不同,句柄可能是同步打开的。当异步打开时,BeginRead和BeginWrite方法在大的读或写时性能更好,但它们可能会慢得多对于小的读或写。如果应用程序被设计为异步I/O的优点,将useAsync参数设置为true。正确使用异步I/O可以提高应用程序的速度在不重新设计应用程序的情况下使用它对于异步I/O,可能会使性能降低一个因素10 .

您必须确保实现APM模式的每个特定方法真正使用真正的异步工作。