繁体   English   中英

如何在没有其他线程的情况下执行等待任务

[英]How is a task with await executed with no additional threads

这是该问题的后续问题:

如果async-await没有创建任何其他线程,那么它如何使应用程序响应?

和这篇博客文章:

http://blog.stephencleary.com/2013/11/there-is-no-thread.html

关于链接问题的可接受答案。他描述了调用await时发生的步骤。

他在第3和第4步中写道,当发生这种情况时,当前线程将返回到调用上下文,从而使消息循环可用于接收其他消息,从而使应用程序做出响应。 然后在第5步中,他写道,我们调用await的任务现在已完成,并且原始方法的其余部分在收到新消息以继续该方法的其余部分之后继续进行。

我不了解的是,如果没有新线程,并且原始线程正忙于调用上下文,那么从头开始如何精确执行该任务?

因此,我转到了博客文章,该文章描述了整个操作实际上是如何在低得多的层次上完成的(老实说,我真的不知道它们是如何工作的),然后只是一个通知它已经完成了...但是我不明白为什么在执行此任务时突然想到,您可以依靠其他硬件来进行计算,而不是依靠CPU,从而以某种方式使得不创建新线程成为可能。如果此任务是一些复杂的计算,那该怎么办?我们不需要CPU吗? 然后我们回到我在写的内容,即当前线程已经在忙于调用上下文了……

但是我不明白为什么在执行此任务时突然可以依靠其他硬件来进行计算,而不是依靠CPU来以某种方式使不创建新线程成为可能。

因为CPU不仅是硬件设备集中并行性的来源。

线程在逻辑上与CPU相关,因此对于任何与CPU绑定的工作负载,我们要么通过创建线程来显式使用线程,要么使用更高级别的机制(例如线程池或Task.Run或隐式使用线程-每个应用程序无论如何都在某个默认线程内启动。

但是还有另一种操作-输入/输出操作,这意味着使用CPU-RAM硬件设备以外的其他设备,例如磁盘,网络适配器,键盘,各种外围设备等。此类设备处理传入和传出的数据。异步-没有人知道您下次何时按下键或网络中有新数据到达。 为了处理异步,这样的硬件设备能够在不占用CPU的情况下传输数据(简单地说,设备在RAM所在的地址中提供了一些地址,然后数据可以自己进行传输)。 这是一个非常简单的描述,但是您可以认为大多数异步流都以它结尾。 如您所见,此处不需要CPU,因此无需创建新线程。 至于入站数据,该机制非常相似,唯一的区别是,一旦数据到达,它将被放入特定的RAM区域以供进一步使用。 当设备完成数据转换(入站或出站)时,它将发出称为中断的特定信号,以通知CPU操作完成,并且CPU对中断做出反应,并触发通常位于硬件设备驱动程序中的特定代码执行-这样,驱动程序可以将通知发送到更高级别。 中断可能来自异步设备,CPU必须暂停当前正在执行的任何当前执行,并切换到中断处理程序。 当设备驱动程序正在执行中断处理程序时,它会将有关I / O完成的通知发送到更高级别的OS堆栈,最后,该通知将触发启动I / O操作的应用程序。 如何完成主要取决于应用程序所运行的操作系统。 对于Windows,有一种称为I / O完成端口的特定机制,该机制意味着使用某些线程池来处理I / O完成通知。 这些通知最终从CLR发送到应用程序,并触发继续执行,最终可以在单独的线程上运行,该线程可以是I / O线程池中的线程,也可以是任何其他线程,具体取决于特定的等待者实现。

至于您所引用的文章的总体思路,可以用以下措辞来表述: async/await后面没有线程,除非您明确创建它,因为await/async本身只是高级通知框架,可以扩展与下面的任何异步机制一起使用。

我不了解的是,如果没有新线程,并且原始线程正忙于调用上下文,那么从头开始如何精确执行该任务?

请务必注意, 任务两种类型:我称为委托任务和承诺任务 委派任务是并行处理中使用的任务类型-原始的任务并行库使用方式,其中任务表示要执行的一定数量的代码。

另一方面,Promise Tasks仅提供已完成某事的通知(以及该操作的结果/异常)。 Promise Tasks不执行代码。 它们是回调的对象表示。 async总是使用Promise Tasks。

因此,当async方法返回Task ,该任务就是Promise Task。 它不会“执行”,但可以“完成”

我认为您需要了解使async / await代码工作的编译器的级别。

采取这种方法:

public async Task<int> GetValue()
{
    await Task.Delay(TimeSpan.FromSeconds(1.0));
    return 42;
}

编译后,您会得到:

[AsyncStateMachine(typeof(<GetValue>d__1))]
public Task<int> GetValue()
{
    <GetValue>d__1 stateMachine = default(<GetValue>d__1);
    stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
    stateMachine.<>1__state = -1;
    AsyncTaskMethodBuilder<int> <>t__builder = stateMachine.<>t__builder;
    <>t__builder.Start(ref stateMachine);
    return stateMachine.<>t__builder.Task;
}

[StructLayout(LayoutKind.Auto)]
[CompilerGenerated]
private struct <GetValue>d__1 : IAsyncStateMachine
{
    public int <>1__state;

    public AsyncTaskMethodBuilder<int> <>t__builder;

    private TaskAwaiter <>u__1;

    private void MoveNext()
    {
        int num = <>1__state;
        int result;
        try
        {
            TaskAwaiter awaiter;
            if (num != 0)
            {
                awaiter = Task.Delay(TimeSpan.FromSeconds(1.0)).GetAwaiter();
                if (!awaiter.IsCompleted)
                {
                    num = (<>1__state = 0);
                    <>u__1 = awaiter;
                    <>t__builder.AwaitUnsafeOnCompleted(ref awaiter, ref this);
                    return;
                }
            }
            else
            {
                awaiter = <>u__1;
                <>u__1 = default(TaskAwaiter);
                num = (<>1__state = -1);
            }
            awaiter.GetResult();
            result = 42;
        }
        catch (Exception exception)
        {
            <>1__state = -2;
            <>t__builder.SetException(exception);
            return;
        }
        <>1__state = -2;
        <>t__builder.SetResult(result);
    }

    void IAsyncStateMachine.MoveNext()
    {
        //ILSpy generated this explicit interface implementation from .override directive in MoveNext
        this.MoveNext();
    }

    [DebuggerHidden]
    private void SetStateMachine(IAsyncStateMachine stateMachine)
    {
        <>t__builder.SetStateMachine(stateMachine);
    }

    void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
    {
        //ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
        this.SetStateMachine(stateMachine);
    }
}

正是IAsyncStateMachine.MoveNext()允许允许调用代码在到达await时退出。 注意return; if (!awaiter.IsCompleted)

这只是一台状态机,可以完成所有的工作。

暂无
暂无

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

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