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

时间:2014-08-04 15:24:20

标签: c# .net asynchronous

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

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

2 个答案:

答案 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模式的每个特定方法都真正使用真正的异步工作。