异步方法在同一个线程上运行,没有时间延迟

时间:2017-02-14 23:08:25

标签: c# .net multithreading async-await

这是AsyncMethods类的样子:

public class AsyncMethods
{
    public static async Task<double> GetdoubleAsync()
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
        return 80d;
    }
    public static async Task<string> GetStringAsync()
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
        return "async";
    }
    public static async Task<DateTime> GetDateTimeAsync()
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(1000);
        return DateTime.Now;
    }
}

这是我的主要方法:

static void Main(string[] args)
{
    while (Console.ReadLine() != "exit")
    {
        Console.WriteLine("Thread.CurrentThread.ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
        DateTime dt = DateTime.Now;
        var res = GetStuffAsync().Result;
        var ts = DateTime.Now - dt;
        Console.WriteLine(res);
        Console.WriteLine("Seconds taken: " + ts.Seconds + " milliseconds taken: " + ts.Milliseconds);
    }
    Console.ReadLine();
    return;
}
static async Task<object> GetStuffAsync()
{
    var doubleTask = AsyncMethods.GetdoubleAsync();
    var StringTask = AsyncMethods.GetStringAsync();
    var DateTimeTask = AsyncMethods.GetDateTimeAsync();

    return new
    {
        _double = await doubleTask,
        _String = await StringTask,
        _DateTime = await DateTimeTask,
    };
}

从每种方法中可以看出,我增加了1秒的延迟。这是输出:

Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
{ _double = 80, _String = async, _DateTime = 2/15/2017 4:32:00 AM }
Seconds taken: 1 milliseconds taken: 40

Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
Thread.CurrentThread.ManagedThreadId: 10
{ _double = 80, _String = async, _DateTime = 2/15/2017 4:32:03 AM }
Seconds taken: 1 milliseconds taken: 16

现在我有两个问题:

  1. 为什么一切都发生在一个线程上?
  2. 当我等了3秒钟时,为什么延迟只有1秒?

4 个答案:

答案 0 :(得分:12)

首先:如果您有两个问题请提出两个问题。不要在一个问题中提出两个问题。

  

为什么一切都发生在一个线程上?

这是一个错误的问题。正确的问题是:为什么你认为任何事情都应该发生在第二个线程上?

在这里,我给你一个任务:等五分钟,然后查看你的电子邮件。在你等待的时候,做一个三明治。 您是否需要雇人才能做等待或制作三明治?显然不是。线程是工人。如果工作可由一名工人完成,则无需雇用工人。

如果您不需要,await的重点是避免进入额外的主题。在这种情况下,你不需要。

  

为什么延迟时间仅为1秒,等待3秒钟?

比较这两个工作流程。

  • 等五分钟;在你等待的时候,做一个三明治
  • 然后查看您的电子邮件
  • 然后等五分钟;在你等待的时候,做一个三明治
  • 然后查看您的电子邮件
  • 然后等五分钟;在你等待的时候,做一个三明治
  • 然后查看您的电子邮件

如果您执行该工作流程,您将等待总共十五分钟。

您编写的工作流程是:

  • 等五分钟
  • 同时等待五分钟
  • 同时等待五分钟
  • 在你等待的时候,做一个三明治
  • 然后查看您的电子邮件

您只需等待五分钟即可完成该工作流程;所有延迟都是在同一时间发生的。

你现在看到你的程序编写错误吗?

要理解的关键洞察力是等待是程序中的一个点,其中await的延续被延迟到等待任务完成之后

如果您没有等待,该程序将自行继续,无需等待。这就是await的含义。

答案 1 :(得分:1)

他们在同一个线程上启动。当您按顺序调用三个异步方法时,它们都会同步执行,直到第一个await调用。 (在await之后,它们成为状态机,只要它们被安排就会从它们停止的地方开始。如果你在<{em> await Task.Delay电话之后检查了线程ID ,你可能会发现延续在不同的线程上运行 - 至少在控制台应用程序中运行。)

至于为什么它只延迟1秒......这就是你告诉它要做的事情。您有三个异步任务,所有任务同时运行,每个延迟一秒钟。你不是说&#34; [a]等到第一个任务完成后再开始第二个任务&#34; - 实际上你正在小心翼翼地做相反的事情,从三个开始然后等待所有三个 - 所以它们并行运行。

答案 2 :(得分:0)

您的Console.WriteLine()调用GetdoubleAsync(),GetStringAsync()和GetDateTimeAsync()在调用线程中发生,因为它们发生在第一次继续之前。

你的await Task.Delay()调用使线程返回到调用代码。

当Task.Delay()返回的任务完成后,这些任务的继续返回其值并将其任务设置为已完成。

这使得GetStuffAsync()中的3个等待(按顺序,同步顺序)返回。在标记为完成之前,每个人都必须等待1秒,但他们同时正在屈服并发生。

我认为您正在寻找System.Threading.Tasks.Parallel来同时执行操作。 Async ... await对于产生线程非常有用。

答案 3 :(得分:0)

您同时启动所有任务,这样他们就可以并行运行,而不是按顺序运行。这就是为什么一切都在1000毫秒后完成的原因。

此外,async不会创建新线程,它会异步使用当前线程。您可以在异步javascript(这是一个单线程环境)或Unity3D中的协程中看到这种行为。它们都允许没有线程的异步行为。

因此,您的每个任务都在同一个线程上运行,并在1秒内完成。