1

我正在调查异步,我遇到了以下我无法解释的结果。

下面的代码(可以复制/粘贴到 Linqpad 或类似代码中)对我来说给出了使用线程池中的三个线程的令人惊讶的结果。

void Main()
{
    Wait();
}

public async void Wait()
{
    Print ("Wait() called. Calling GetAnswer()");
    var t = await GetAnswerAsync3();
    Print("Result of Wait(): " + t);
}

public Task<bool> GetAnswerAsync3()
{
    return Task.Run(() => {
            // Thread.Sleep(1000);
        Print("GetAnswerAsync3() called");
        return true;
    });
}

public void Print(string message)
{
    Console.WriteLine ("Thread: " + Thread.CurrentThread.ManagedThreadId + " - " + message);
}

结果是:

Thread: 35 - Wait() called. Calling GetAnswer()
Thread: 51 - GetAnswerAsync3() called
Thread: 43 - Result of Wait(): True

表明涉及三个线程。

现在。如果我在它返回之前添加一个Thread.Sleep(1000)返回的任务GetAnswerAsync3,结果现在只有两个线程在运行!也许这可能是因为线程池重用了一个线程?

为什么这里有三个不同的线程在起作用?

4

1 回答 1

3

一个async方法被分解成几个工作,在这种情况下,这些工作都被调度到线程池中。await指定async方法可能被“破坏”的地方。

第一个线程是主线程,它不是线程池的一部分。

第二个线程是用于执行传递给的委托的线程Task.Run。这可以是线程池上的任何线程。

第三个线程是用于Wait在其await. 这也可以是线程池上的任何线程。

从概念上讲,这就是发生的事情。实际上,它有点复杂:

我认为第一个更容易解释Thread.Sleep。在这种情况下,在完成之前Wait已被其完全挂起。当完成时,它执行它的延续,并且方法的延续已经设置(在我的博客上描述)。因此,运行的同一线程实际上继续执行而不会产生。awaitTask.RunTask.RunasyncExecuteSynchronouslyThread.SleepWait

你的原始代码有一个竞争条件:Task.Run很短,所以它会很快完成。您所看到的是Wait检查Task并看到它尚未完成并暂停该Wait方法。同时,Task.Run完成并将剩余的调度Wait到线程池中。

如果您想了解有关如何await使用上下文的更多信息,我推荐我的asyncintro。你通常不必担心这样的细节。

于 2013-07-01T17:38:26.780 回答