如何使用async和await正确处理

Yul*_*dra 15 .net c# multithreading dispose async-await

我正在努力使代码替换ThreadTask.睡眠/延迟只是代表长时间运行的活动.

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

3秒后的结果test.txt仅为

线程处理

我需要按顺序改变什么才能TaskDispose::Dispose执行ThreadDispose

Yuv*_*kov 22

让我们隔离每段代码:

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

public void RunAsync()
{
    ThreadPool.QueueUserWorkItem(state =>
    {
        Thread.Sleep(3000);
    });
}
Run Code Online (Sandbox Code Playgroud)

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

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);
   }
}
Run Code Online (Sandbox Code Playgroud)

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

您的代码会点击await关键字并将控制权返回给您的Main方法.在内部Main,您的异步方法是要执行的最后一段代码,因此完成了您的应用程序,并且没有机会让您的Dispose方法执行.

如果你想将其配置,你就必须从改变返回类型voidTask并明确Wait:

public static async Task TaskDoWork()
{
    using (var dispose = new TaskDispose())
    {
       await dispose.RunAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在:

static void Main(string[] args)
{
    ThreadDoWork();
    TaskDoWork().Wait();
}
Run Code Online (Sandbox Code Playgroud)

边注:

应遵循以下几条准则:

  1. async void为了与事件处理程序兼容,在该范围之外很少会出现应该使用它的情况.相反,使用async Task.

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

  3. 使用WaitTask可能会导致死锁.在这种特殊情况下,它不会,因为控制台应用程序没有SynchronizationContext并使用线程池.推荐的方法是"一直异步"并使用await

async-await标签wiki里面有很棒的阅读材料,请务必查看.