异步任务 c#

3

我正在尝试理解C#中的异步编程。我创建了一个示例函数,可以仅调用一次。例如读取大文件。我想创建一个查询,并在查询中等待请求,直到它们可以安全地读取文件。

AsyncWork aw = new AsyncWork();

Task.Run(() => {
    for (int count = 0; count < 10; count++) {
        aw.DoAsyncWork(count);
        Console.WriteLine("request added");
    }
});
Console.ReadKey();

以及AsyncWork

public class AsyncWork {
    int Requests = 0;
    int Workers = 0;

    public AsyncWork() { }

    public async Task DoAsyncWork(int count) {
        Requests++;

        while (Workers > 0) ;

        Workers++;
        Requests--;

        if (Workers > 1) Console.WriteLine("MORE WORKERS AT ONCE");

        Console.WriteLine(count.ToString() + " Started task");
        //reading from file
        await Task.Delay(1000);
        Console.WriteLine(count.ToString() + " Ended task");

        Workers--;
    }
}

我原本期望有10个请求,然后逐个完成。但实际输出的情况是:

0 Started task
request added
0 Ended task
1 Started task
request added
1 Ended task
2 Started task
request added
2 Ended task
3 Started task
request added
3 Ended task
4 Started task
request added
4 Ended task
5 Started task
request added
5 Ended task
6 Started task
request added
6 Ended task
7 Started task
request added
7 Ended task
8 Started task
request added
8 Ended task
9 Started task
request added
9 Ended task

为什么它在同步运行?

你的方法 DoAsyncWork 是异步执行的,但是在任务中有一个循环,每次该方法都会执行,那么你期望发生什么? - Markiian Benovskyi
我原本以为,没有await的异步方法会被启动,主程序将继续执行下一行代码,而循环将在另一个异步任务中执行。 - 110mat110
你没有运行任何异步操作,因为你的 Lambda 函数没有标记为 async,并且你没有使用 await 来等待 DoAsyncWork 的执行。 - Kenneth K.
@KennethK。那不是真的。调用异步方法而不等待它并不会使该方法同步,而是使其异步,这意味着该方法将继续执行而不必等待异步方法完成,这很少是可取的,但肯定是可能的,并且是异步的。 - Servy
这是什么意思: while (Workers > 0) ; - FCin
它会让所有请求等待(陷入循环),而只允许一个请求进行工作。 - 110mat110
1个回答

4
当您运行代码时,第一个工作线程将开始工作,然后下一个线程将被卡在您的忙等待循环中,while (Workers > 0) ;并且直到前一个线程完成后才能继续。然后当它启动下一个工作线程时,该线程也会卡在那里,以此类推,对于每个迭代中启动工作者的循环,都会出现这种情况。

因此,您只有最多一个工作线程在工作,而有一个工作线程在等待其完成,从而占用了整个CPU。
编写异步代码时同步访问的正确方式是使用SemaphoreSlim并使用WaitAsync,它将异步等待信号量可用,而不是同步阻塞线程(同时占用CPU),以使其他工作者完成。 它还具有安全地从多个线程访问的优点,而不像整数一样从多个线程安全更改。

哦,所以一个陷入循环的工作线程会阻塞主线程创建其他工作线程吗?我没想到在多核处理器上会出现这种情况。 - 110mat110
@110mat110 好吧,你正在一个线程池线程上运行整个外部循环,而不是主线程,但它们仍然都在同一个线程池线程中运行。只有在调用安排工作在另一个线程上运行的操作(即Task.Run)时,它才会使用多个线程。当然,如果你实际上在另一个线程中运行该代码,你将引入更多问题(因为如前所述,你没有正确地同步访问整数)。目前,你永远不会有多个线程同时操作它。 - Servy
好的,我明白了,async并不意味着多线程,我把它和任务混淆了。我还有很多要学习的。 - 110mat110

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接