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

问题描述 投票:5回答:2

我对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# .net asynchronous
2个回答
5
投票

如果你没有在BeginRead中使用AsyncCallback参数,那么只有一个线程在你的程序中运行代码。这使用IO完成端口通过在IO线程池中的线程上运行少量代码来完成IO完成时的信号,以更新操作的状态。当您调用EndRead时,它将阻止当前线程,直到IO操作完成。它是异步的,当你开始读取操作时,当前线程除了等待IO硬件执行读取操作之外不需要做任何事情,所以你可以在此期间做其他事情,然后决定你想什么时候停止并等待IO完成。

如果确实传入了AsyncCallback,那么当IO操作完成时,它将在IO线程池线程上执行少量代码,这将触发您的回调方法在.NET线程池的线程上执行。


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

© www.soinside.com 2019 - 2024. All rights reserved.