如何使用异步和等待正确处理

尤里亚姆·钱德拉

我试图从使代码替换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.txt3秒后的结果

线程处理

我需要更改什么以使命令TaskDispose::Dispose始终像执行一样ThreadDispose

尤瓦尔·伊茨恰科夫(Yuval Itzchakov)

让我们隔离每段代码:

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执行方法的机会

如果要处理它,则必须将返回类型从更改为voidTask并显式地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. 使用WaitTask可能会导致死锁。在此特定情况下,这不是因为控制台应用程序没有SynchronizationContext并使用线程池。推荐的方法是“一直异步”并使用await

async-await标签wiki内有很多阅读材料,请务必检查一下。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章