如何使用async和await正确处理

时间:2014-08-03 16:38:25

标签: c# .net multithreading async-await dispose

我正在尝试从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");
    }
}

test.txt中3秒后的结果仅为

  

线程处理

我需要更改TaskDispose::Dispose按顺序执行的更改ThreadDispose

2 个答案:

答案 0 :(得分:22)

让我们隔离每段代码:

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

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

您在第一段代码中所做的是在线程池线程上进行队列工作。因为您在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);
   }
}

当你在方法中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. Wait上使用Task会导致死锁。在这种特殊情况下,它并不是因为控制台应用程序没有SynchronizationContext并使用线程池。推荐的方法是一直“异步”#34;并使用await

  4. async-await tag wiki内有很棒的阅读材料,请务必查看。

答案 1 :(得分:-1)

这两个例子都有问题。 第一个,在线程的情况下,Dispose方法在线程结束之前调用。 在任务的情况下,任务完成后将调用Dispose方法。

但是文件只有线程大小写的文本,因为在调用RunAsync方法后它会被同步调用。并且任务案例不会写任何内容,因为应用程序在任务完成之前已经结束。

测试等待任务完成Thread.Sleep(5000),例如在Main方法结束时,任务应写入输出文件。