【问题标题】:If you kill the thread that started a `async` task, do you kill the task?如果你杀死启动“异步”任务的线程,你会杀死这个任务吗?
【发布时间】:2020-01-22 19:05:53
【问题描述】:

async方法的缺陷之一是操作可以在不同的线程上执行。这可以通过以下方式验证:

var z = 0;
while (z < 20)
{
   Console.Write(" - Thread: " + Thread.CurrentThread.ManagedThreadId);
   await Task.Delay(1000);
   z++;
}

这将输出类似:
- Thread: 1 - Thread: 1 - Thread: 4 - Thread: 6 - Thread: 7 - Thread: 4

在常规方法中,如果您使用:

var z = 0;
while (z < 20)
{
   Console.Write(" - Thread: " + Thread.CurrentThread.ManagedThreadId);
   Thread.Sleep(1000);
   z++;
}

您的输出将是:
- Thread: 1 - Thread: 1 - Thread: 1 - Thread: 1 - Thread: 1 - Thread: 1

现在,如果您将第一个代码封装在 Thread 上,如下所示:

var thread = new Thread(new ThreadStart(async () =>
{
    var z = 0;
    while (z < 20)
    {
        Console.WriteLine("Thread: " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
        z++;
    }
}));
thread.Start();

如果你 thread.Abort 你会可靠地杀死 async 运行的操作吗?

【问题讨论】:

  • 线程中止后的几乎所有事情都是未定义的行为;不要那样做!
  • 任务或线程,如果你想能够“取消”,你应该使用 CancellationToken 来通知线程停止工作,正如@Fabjan 所说的“混合线程与异步代码'气味'并且不推荐”
  • Thread.Abort() 没有什么可靠的。这会在线程上引发异常。很多事情都可能发生……例如,考虑 try-catch-finally 块。

标签: c# multithreading async-await task-parallel-library


【解决方案1】:

异步方法的思想是操作可以在不同的线程上执行。

没有。 async 方法的想法是一种可以在另一个操作正在进行时暂停然后可以稍后恢复的方法。一些async 方法可以在不同的线程上恢复;其他人不能。

如果你 thread.Abort 你会可靠地终止正在运行的异步操作吗?

没有。一旦该方法遇到第一个await,线程就会退出。如果Thread.Abort 在线程到达await 之前运行,代码将被中止。如果Thread.Abort 在线程执行await 之后运行,则线程已经退出。

【讨论】:

    【解决方案2】:

    异步方法的思想是操作可以在 不同的线程。

    异步方法的思想是操作需要异步执行,不一定在单独的线程上。一些 I/O 操作不需要线程池线程,而是在 I/O 线程上执行。

    我会考虑以下几点:

    • 关键字await 创建一个状态机来处理异步操作并且它是继续的。

    • 混合线程与async 代码“有味道”,不推荐。

    • 1234563 @操作结束,如果它处于故障状态,您将无法处理它。
    • .Net Core 不支持 Thread.Abort 方法,如果你运行它,你会看到:

      “未处理的异常。System.PlatformNotSupportedException:此平台不支持线程中止”

    【讨论】:

      【解决方案3】:

      您是否尝试过使用调试器单步执行此代码?我认为你会发现,因为在ThreadStart 内部没有等待async,所以线程在遇到第一个await 时立即完成,并且循环将被终止。

      为什么?因为async/await 的设计目的不是在多个线程上执行方法。它可以这样做是其目的的副产品。

      它的设计目的是允许在调用堆栈的某个时刻,线程在继续工作的异步部分时执行其他操作(例如侦听 UI 输入)。 await 的行为是将控制权返回给父调用者。由于没有父调用者,线程终止于await

      您可能对my answer here 感兴趣,这里有更详细的解释。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-05-29
        • 2019-05-19
        • 2019-08-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多