gpt4 book ai didi

c# - 如何使用 async 和 await 正确处理

转载 作者:可可西里 更新时间:2023-11-01 07:44:43 27 4
gpt4 key购买 nike

我正在尝试将代码从 Thread 替换为 Task。 sleep /延迟仅代表长时间运行的事件。

static void Main(string[] args)
{
ThreadDoWork();
TaskDoWork();
}
public static void ThreadDoWork()
{
using (var dispose = new ThreadDispose())
{
dispose.RunAsync();
}
}
public static async void TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}
public class ThreadDispose : IDisposable
{
public void RunAsync ()
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(3000);
});
}
void IDisposable.Dispose()
{
File.AppendAllText("D:\\test.txt", "thread disposing");
}
}
public class TaskDispose : IDisposable
{
public async Task RunAsync()
{
await Task.Delay(3000);
}
void IDisposable.Dispose()
{
File.AppendAllText("D:\\test.txt", "task disposing");
}
}

test.txt中3秒后的结果只有

thread disposing

我需要更改什么才能使 TaskDispose::Dispose 始终像 ThreadDispose 一样执行?

最佳答案

让我们分离出每段代码:

public static void ThreadDoWork()
{
using (var dispose = new ThreadDispose())
{
dispose.RunAsync();
}
}

public void RunAsync()
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(3000);
});
}

您在第一段代码中所做的是在线程池线程上进行队列工作。因为您在 using 范围内运行此代码,并且它在不同的线程上异步运行,所以它会立即 处理。这就是您在文本文件中看到处置消息的原因。

public static async void TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}

public class TaskDispose : IDisposable
{
public async Task RunAsync()
{
await Task.Delay(3000);
}
}

当你在你的方法中await时,你实际上说的是:“执行这段代码。因为它本质上是异步的,我会将控制权返回给调用者方法,请在完成异步操作后给我回电话"

您的代码命中 await 关键字并将控制权返回给您的 Main 方法。在 Main 中,您的异步方法是要执行的最后一段代码,因此完成了您的应用程序,并且不给您的 Dispose 方法执行机会。

如果你想处理它,你必须将返回类型从 void 更改为 Task 并显式地 Wait:

public static async Task TaskDoWork()
{
using (var dispose = new TaskDispose())
{
await dispose.RunAsync();
}
}

现在:

static void Main(string[] args)
{
ThreadDoWork();
TaskDoWork().Wait();
}

旁注:

应遵循一些准则:

  1. async void 是为了与事件处理程序兼容,很少有超出该范围的场合应该使用它。相反,请使用 async Task

  2. 使用 TAP(任务异步模式)进行异步操作的方法应该以 Async 后缀结尾。 TaskDoWork 应该是 TaskDoWorkAsync

  3. Task 上使用 Wait 会导致死锁。在这种特殊情况下,它不是因为控制台应用程序没有 SynchronizationContext 并使用线程池。推荐的方法是“一路异步”并使用 await

async-await tag wiki 里面有很棒的阅读 Material , 请务必检查一下。

关于c# - 如何使用 async 和 await 正确处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25106787/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com