【问题标题】:Endless async and await?无尽的异步和等待?
【发布时间】:2024-01-24 06:58:02
【问题描述】:

我不了解异步/等待:

async 方法内部必须有一个 await 调用是强制性的……但是如果有一个 await 那是因为它正在调用另一个 async 方法,对吧?因此,它似乎是一个无穷无尽的异步方法链,其中等待内部调用另一个异步方法。

那么是否可以创建一个“第一个”异步方法,而不是在内部调用任何其他异步方法。只需创建一个异步方法,因为该方法会执行大量工作,可能会降低系统速度。

【问题讨论】:

  • "async 方法必须在内部有一个 await 调用是强制性的......" 不,相反:如果您在方法中使用 await,则该方法必须标记为 async .您可以将其标记为异步而不使用等待(但这通常是不正确的)
  • @Dennis_E async 方法没有await 不是必需,但几乎没有合理的理由这样做,因为async 会只是一个谎言。

标签: c# .net asynchronous async-await


【解决方案1】:

首先,一些澄清

方法不需要等待async,相反。您只能在 async 方法中使用 await。你可能有一个方法返回一个Task,但它没有被标记为async。更多here

您的实际问题

IIUC,是关于“所有异步的根源”。 所以,是的,可以创建一个“第一个”async 方法。它只是一个返回Task(或Task<T>)的方法。

这些任务有两种类型:A Delegate Task and a Promise Task

  1. 委托任务由Task.Run 触发(大多数情况下。Task.StartNewnew Task(() => {}); 是其他选项)并且它有代码可以运行。这主要用于卸载工作。
  2. Promise 任务是一个Task,它实际上并不执行任何代码,它只是一种a.等待在完成时收到通知的机制@ 987654340@。 b. 使用Task 发出完成信号。这是通过TaskCompletionSource 完成的,主要用于固有的异步操作(但也用于async synchronization objects),例如:

.

private static Task DoAsync()
{
    var tcs = new TaskCompletionSource<int>();
    new Thread(() =>
    {
        Thread.Sleep(1000);
        tcs.SetResult(5);
    }).Start();

    return tcs.Task;
}

这些工具允许您创建这些“根”,但除非您自己实现 I/O 库(如 .NetDNS 类)或同步对象(如 SemaphoreSlim),否则您很少会使用它们。

【讨论】:

  • 谢谢,您的回答让我可以更多地搜索TaskCompletionSource。为了更好地理解它以及何时使用它,这里有一个 * link。它将带您到this 代码示例。
【解决方案2】:

async 关键字的目的是简单地允许在方法内部使用await,您没有在内部调用另一个async 方法,例如

public async void WaitForSomething()
{
    await Task.Delay(1000);
}

【讨论】:

  • 对。异步的方法只是一个实现细节。您正在等待的只是一个实现“异步模式”的对象(通常是一个任务)。
  • 嗯 2 票否决,需要详细说明吗?据我所知,我的回答在技术上是准确的。
  • @James 假设 OP 没有询问 async 关键字,而是询问异步等待方法调用,那么 “是否可以创建一个“第一个”异步方法,而不是调用任何里面还有其他异步方法吗?”是关于如何实现Task.Delay,而不是如何调用它。
【解决方案3】:

当然,除了使用async 方法之外,确实有创建Task 的方法。

  • 您可以使用任务构造函数(尽管除非您有特别令人信服的理由来创建一个代表您在委托实际开始执行之前使用的委托执行的任务,否则您应该避免这样做。只是使用下一个选项。

  • 可以使用Task现有的方法来创建任务,比如Task.Run代表在另一个线程中执行一个委托,Task.WhenAll代表完成了一系列其他任务, Task.FromAsync基于异步编程等不同模式创建任务。

  • 您可以使用TaskCompletionSource 创建一个您可以随时完成的任务,允许您将任何固有的异步行为转换为Task。固有的异步操作可能是事件触发、回调方法被调用等。

【讨论】:

    【解决方案4】:

    如果你有一个非常密集的方法,它会做很多工作,可能会减慢系统速度,你可以这样调用它。

    public async void CallerAsyncMethod()
    {
        var taskResult = Task.Factory.StartNew(() => IntensiveMethod());
        await taskResult;
    }
    

    这里IntensiveMethod 不是异步方法。

    希望对你有帮助。

    【讨论】:

    • 这根本不能回答问题
    • @Morgoz 需要从异步方法调用非异步方法。这是可以实现的方式。请让我知道我在哪里弄错了。
    • "async 方法必须在内部有一个 await 调用是强制性的......" .... 你的最后有一个权利 - 所以它不是反例(但反对票不是来自我- 我被诱惑了)
    • @CarstenKönig 好吧,这不是因为投反对票……学习更重要。我非常强调调用非异步方法。
    • 是的,但他问是否有可能没有 any await 而你的回答根本没有帮助
    最近更新 更多