简体   繁体   English

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

[英]Async methods running on same thread with no time delay

This is what AsyncMethods class looks like: 这是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;
    }
}

This what my main method looks like: 我的主要方法如下所示:

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,
    };
}

As it can be seen in each method i added a delay of 1 second. 从每种方法可以看出,我增加了1秒的延迟。 Here is the output: 这是输出:

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

Now i have 2 questions: 现在我有2个问题:

  1. How come everything happened on a single thread? 一切如何在单个线程上发生?
  2. Why was the Delay only 1 second when i waited 3 seconds? 为什么等待3秒时延迟只有1秒?

First off: if you have two questions please ask two questions . 首先,如果您有两个问题, 请问两个问题 Don't put two questions in one question. 不要在一个问题中提出两个问题。

How come everything happened on a single thread? 一切如何在单个线程上发生?

That's the wrong question to ask. 这是个错误的问题。 The correct question is: why do you think anything should happen on a second thread? 正确的问题是:您为什么认为第二个线程应该发生任何事情?

Here, I'll give you a task: wait five minutes, and then check your email. 在这里,我将给您一个任务:等待五分钟,然后检查您的电子邮件。 While you're waiting, make a sandwich. 在等待时,做一个三明治。 Did you have to hire someone to either do the waiting or make the sandwich ? 您是否需要雇用某人来做等待或做三明治 Obviously not. 显然不是。 Threads are workers. 线程是工人。 There's no need to hire a worker if the job can be done by one worker. 如果工作可以由一名工人完成,则无需雇用一名工人。

The whole point of await is to avoid going to extra threads if you don't need to. await的全部目的是避免在不需要时使用额外的线程。 In this case you don't need to. 在这种情况下,您不需要。

Why was the Delay only 1 second when i waited 3 seconds? 为什么等待3秒时延迟只有1秒?

Compare these two workflows. 比较这两个工作流程。

  • Wait five minutes; 等待五分钟; while you're waiting, make a sandwich 在等你的时候,做一个三明治
  • then check your email 然后检查您的电子邮件
  • then wait five minutes; 然后等待五分钟; while you're waiting, make a sandwich 在等你的时候,做一个三明治
  • then check your email 然后检查您的电子邮件
  • then wait five minutes; 然后等待五分钟; while you're waiting, make a sandwich 在等你的时候,做一个三明治
  • then check your email 然后检查您的电子邮件

If you execute that workflow, you'll wait a total of fifteen minutes. 如果执行该工作流程,则总共要等待15分钟。

The workflow you wrote was: 您编写的工作流程为:

  • Wait five minutes 等五分钟
  • simultaneously, wait five minutes 同时,等待五分钟
  • simultaneously, wait five minutes 同时,等待五分钟
  • while you're waiting, make a sandwich 在等你的时候,做一个三明治
  • then check your email 然后检查您的电子邮件

You only wait five minutes with that workflow; 您只需等待五分钟即可完成该工作流程。 all the delays happen at the same time. 所有延迟都在同一时间发生。

Do you see how you wrote your program incorrectly now? 您是否看到现在错误地编写程序的方式?

The key insight to understand here is that an await is a point in a program where the continuation of the await is delayed until after the awaited task completes . 在这里要理解的关键见解是, 等待是程序中的一点,其中等待的持续时间被延迟到等待任务完成之后

If you don't put in an await, the program continues by itself without waiting. 如果您不等待,程序将自动继续运行而无需等待。 That's the meaning of await . 那就是await的意思。

They all start on the same thread. 它们都同一线程开始 When you call your three Async methods in sequence, they all execute synchronously up until the first await call. 当您依次调用三个Async方法时,它们都将同步执行直到第一个await调用。 (After the await , they become state machines that pick up where they left off whenever they get scheduled. If you checked the thread ID after the await Task.Delay call, you would probably find that the continuations ran on different threads -- at least here in a console app.) (在await ,它们成为状态机,它们在计划调度时会停下来。如果在await Task.Delay调用之后检查线程ID,您可能会发现延续在不同的线程上运行-至少在控制台应用程序中)。

As for why it's only delaying 1 second... that's what you're telling it to do. 至于为什么只延迟1秒钟...这就是您要告诉它执行的操作。 You've got three async tasks, all running simultaneously, each delaying for one second. 您有三个异步任务,它们同时运行,每个任务都延迟一秒钟。 You're not saying "[a]wait until the first task is done before starting the second" -- in fact you're carefully doing the opposite, starting all three and then awaiting all three -- so they run in parallel. 您并不是说“等到第一个任务完成后再开始第二个任务”,实际上,您正在认真地做相反的事情,先启动所有三个,然后等待所有三个,以便它们并行运行。

Your Console.WriteLine() calls in GetdoubleAsync(), GetStringAsync(), and GetDateTimeAsync() happened in the calling thread because they happened before the first continuation. 您的Console.WriteLine()调用GetdoubleAsync(),GetStringAsync()和GetDateTimeAsync()发生在调用线程中,因为它们发生在第一次继续之前。

Your await Task.Delay() calls yielded the thread back to the calling code. 您的等待Task.Delay()调用使线程返回到调用代码。

When the task returned by Task.Delay() completed, the continuation on those Tasks returned their values and set their tasks as completed. 当Task.Delay()返回的任务完成时,这些Task的继续执行返回其值并将其任务设置为已完成。

This allowed your 3 awaits (in sequential, synchronous order) in GetStuffAsync() to return. 这允许您在GetStuffAsync()中等待3个(按顺序,同步顺序)返回。 Each one had to wait 1 second before marked as completed, but they were yielding and happening at the same time. 每个人都必须等待1秒钟才能标记为已完成,但是它们同时在屈服和发生。

I think you are looking for System.Threading.Tasks.Parallel to do things at the same time. 我认为您正在寻找System.Threading.Tasks.Parallel同时执行操作。 Async...await is useful for yielding threads. 异步...等待对于产生线程很有用。

You're starting all your tasks at the same time so they're all going to run in parallel, not in sequence. 您要同时启动所有任务,因此它们将并行运行,而不是依次运行。 That's why everything completes after 1000 milliseconds. 这就是为什么一切都在1000毫秒后完成。

Additionally, async doesn't create new threads, it uses the current thread asynchronously. 此外, async不会创建新线程,而是异步使用当前线程。 You can see this kind of behaviour in async javascript (which is a single threaded environment) or coroutines in Unity3D. 您可以在异步javascript(这是一个单线程环境)或Unity3D中的协程中看到这种行为。 They both allow async behaviour without threads. 它们都允许没有线程的异步行为。

So each of your tasks is being run on the same thread and completes in 1 second. 因此,您的每个任务都在同一线程上运行,并在1秒内完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM