简体   繁体   English

异步/等待同步运行?

[英]async/await runs synchronously?

Below code is from https://blog.stephencleary.com/2012/02/async-and-await.html I just added some descriptive methods 下面的代码来自https://blog.stephencleary.com/2012/02/async-and-await.html我刚刚添加了一些描述性方法

class Program
{
    async static Task Main(string[] args)
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId); //thread id is 1 here
        await DoSomethingAsync();
        Console.WriteLine("do other workzzz");
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId);  //thread id is 4 here
        Console.ReadLine();
    }

    public static async Task DoSomethingAsync()
    {
        await Task.Delay(2000);    
    }
}

and the author says: 作者说:

I like to think of “await” as an “asynchronous wait”. 我喜欢将“等待”视为“异步等待”。 That is to say, the async method pauses until the awaitable is complete (so it waits), but the actual thread is not blocked (so it's asynchronous). 也就是说,异步方法会暂停直到可等待的操作完成(因此它会等待),但是实际线程不会被阻塞(因此它是异步的)。

so my questions is: why the actual thread(thread id 1 in my case) is not blocked? 所以我的问题是:为什么实际的线程(在我的情况下为线程ID 1)没有被阻塞? From my perspective, a thread is blocked because further statements will not be executed until current method has finished. 在我看来,线程被阻塞是因为在当前方法完成之前不会执行其他语句。 We can see that Console.WriteLine("do other workzzz"); 我们可以看到Console.WriteLine("do other workzzz"); won't be executed until DoSomethingAsync() finishes, isn't it kind of blocking? 在DoSomethingAsync()完成之前将不会执行,不是一种阻塞吗?

Another important thing to notice is, after DoSomethingAsync(); 注意的另一件事是在DoSomethingAsync(); finishes, thread id changes from 1 to 4, there is no "actual thread" anymore. 完成后,线程ID从1更改为4,不再有“实际线程”。 Why thread 1 disappear? 为什么线程1消失了? shouldn't it be the thread 4 to disappear? 是不是线程4消失了?

(Original question was along the lines of: "What do you call an async method when you await it rather than letting it run in parallel?") (最初的问题是:“等待异步方法而不是让它并行运行时,您将其称为什么?”)

The word I would use is "sequentially". 我将使用“连续”这个词。 They are running one at a time, in sequence. 他们一次一次运行。 But that type of task ( async ) is still asynchronous, due to the way it is scheduled and executed. 但是由于计划和执行的方式,该类型的任务( async )仍然是异步的。 It's more than just the caller that decides whether it is asynchronous or not. 不仅仅是调用者来决定它是否异步。 (Additionally, the caller is async , and its caller will also be async , so you really can't call an asynchronous task synchronously. (If you try, using functions like Wait() , you risk deadlocks. Because under the hood, it's not the same as a synchronous function.) (此外,调用方是async ,其调用方也将是async ,因此您实际上无法同步调用异步任务。(如果尝试使用类似Wait()函数,则可能会出现死锁。因为在后台,它是与同步功能不同。)

I think the lack of variable assignments in part B is confusing you. 我认为B部分缺少变量分配会使您感到困惑。

Part B can be rewritten as this: B部分可以这样重写:

var a = Task.Delay(1000);
await a;

var b = Task.Delay(1000);
await b;

var c = Task.Delay(1000);
await c;

etc...

If you invoke all the tasks at the beginning and await them all at the end (as in part A), then you can think of it as those tasks running in parallel. 如果在开始时调用所有任务,然后在结束时等待所有任务(如A部分),则可以将其视为并行运行的那些任务。

await means to wait for the task (in this case, Task.Delay(1000) ) to complete before moving on. await表示在继续之前等待任务(在本例中为Task.Delay(1000) )完成。 Without the await , you can think of the task as being run in the background (but the main program can exit before it reaches completion) 如果没有await ,您可以将任务视为在后台运行(但是主程序可以在完成之前退出)

To wait until all tasks are finished before the program exits, you can do something like this: await Task.WhenAll(taskA, taskB, …); 要等到所有任务完成后再退出程序,可以执行以下操作:a。 await Task.WhenAll(taskA, taskB, …);

Async operations are handled differently than other methods. 异步操作的处理方式与其他方法不同。

Simplified explanation: your code.. 简化解释:您的代码

 async static Task Main(string[] args) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); //thread id is 1 here await DoSomethingAsync(); Console.WriteLine("do other workzzz"); Console.WriteLine(Thread.CurrentThread.ManagedThreadId); //thread id is 4 here Console.ReadLine(); } 

Gets executed as follows: 执行如下:

The calling thread executes.. 调用线程执行。

Console.WriteLine(Thread.CurrentThread.ManagedThreadId);

The code waited upon by the await statement gets dispatched to the task scheduler, which uses a synchronization context to queue, schedule and execute it. await语句等待的代码被分派到任务调度程序,该任务调度程序使用同步上下文对其进行排队,调度和执行。 The implementation of the synchronization context is responsible for deciding which thread this code executes in. 同步上下文的实现负责确定此代码在哪个线程中执行。

 await DoSomethingAsync();

The code after the await gets posted back to synchronization contex captured at the start. await之后的代码将回发到开始时捕获的同步上下文。 Again, depending on the implemenation, some other thread might execute it. 同样,根据实现,其他一些线程可能会执行它。

Console.WriteLine("do other workzzz");
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.ReadLine(); 

Eventhough the code reads synchronously, the async/await pattern will break up the flow. 即使代码是同步读取的, async/await模式也会破坏流。

why the actual thread(thread id 1 in my case) is not blocked? 为什么实际的线程(在我的情况下为线程ID 1)没有被阻塞?

When await is used on an awaitable that is not complete, then that await returns from the async method. await上的awaitable不是完全使用,那么await来自返回 async方法。 The calling thread continues executing its next piece of code. 调用线程继续执行其下一段代码。

We can see that Console.WriteLine("do other workzzz"); 我们可以看到Console.WriteLine(“ do other workzzz”); won't be executed until DoSomethingAsync() finishes, isn't it kind of blocking? 在DoSomethingAsync()完成之前将不会执行,不是一种阻塞吗?

It doesn't block a thread. 它不会阻塞线程。 The method is "paused" at the point of the await , but there's no thread holding it in place. 该方法在await被“暂停”,但是没有线程将其固定在适当的位置。

For example, examine your call stack before the await and again after the await . 例如,检查之前调用栈await和后再次await You'll see that the call stack is not preserved, because the async method returned and the original thread continued running. 您将看到保留调用堆栈,因为返回了async方法并且原始线程继续运行。 After the await , that call stack is not re-entered. await不会重新进入该调用堆栈。

Another important thing to notice is, after DoSomethingAsync(); 注意的另一件事是在DoSomethingAsync()之后; finishes, thread id changes from 1 to 4, there is no "actual thread" anymore. 完成后,线程ID从1更改为4,不再有“实际线程”。 Why thread 1 disappear? 为什么线程1消失了? shouldn't it be the thread 4 to disappear? 是不是线程4消失了?

Both threads 1 and 4 are actual threads. 线程1和4均为实际线程。 Thread 1 is the main thread, the one that starts the Console application. 线程1是主线程,它是启动Console应用程序的主线程。 Thread 4 is a thread pool thread. 线程4是线程池线程。

When DoSomethingAsync finishes and the await is ready to resume its async method, it has to resume it somewhere . DoSomethingAsync完成并且await已准备好恢复其async方法时,它必须在某个地方恢复它。 By default an await will capture a "context"; 默认情况下, await将捕获“上下文”。 for a console application, this is the thread pool context. 对于控制台应用程序,这是线程池上下文。 So when the async method resumes, it resumes on a thread pool thread. 因此,当async方法恢复时,它将在线程池线程上恢复。

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

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