草庐IT

c# - 等待最后一次时不必要的异步/等待?

coder 2024-05-21 原文

我最近一直在处理 async await(阅读所有可能的文章,包括 Stephen 和 Jon 的最后两章),但我已经得出结论,但我不知道它是否是100% 正确。 - 因此我的问题。

因为 async 只允许出现 await 这个词,所以我将把 async 放在一边。

AFAIU,等待就是延续。与其编写功能性(连续)代码,不如编写同步代码。 (我喜欢将其称为可回调代码)

因此,当编译器到达 await 时 - 它会将代码拆分为 2 个部分,并注册第二部分以在第一部分完成后执行(我不知道为什么这个词未使用 callback - 这正是完成的操作)。 (同时工作 - 线程回来做其他事情)。

但是看看这段代码:

public async  Task ProcessAsync()
        {
           Task<string> workTask = SimulateWork();
           string st= await workTask;
           //do something with st
        }

 public    Task <string> SimulateWork()
        {
            return ...
        }

当线程到达 await workTask; 时,它将方法拆分为 2 个部分。所以在 SimulateWork 完成后 - 方法的延续:又名://do something with st - 被执行。

一切顺利

但是如果方法是:

public async  Task ProcessAsync()
        {
           Task<string> workTask = SimulateWork();
           await workTask; //i don't care about the result , and I don't have any further commands 
        }

这里 - 我不需要需要 continuation ,意思是 - 我不需要 await 来拆分方法,这意味着 - 我不需要 async/await 完全在这里!但我仍然会得到相同的结果/行为!

所以我可以这样做:

   public void ProcessAsync()
            {
               SimulateWork();
            }

问题:

  • 我的诊断是否 100% 正确?

最佳答案

所以,你认为 await正如问题的标题所暗示的那样,下面是多余的:

public async Task ProcessAsync()
{
    Task<string> workTask = SimulateWork();
    await workTask; //i don't care about the result , and I don't have any further 
}

首先,我假设 “当 await 是最后一个” 你的意思是 “当 await 是唯一的 await "。必须是这样,否则以下内容将无法编译:

public async Task ProcessAsync()
{
    await Task.Delay(1000);
    Task<string> workTask = SimulateWork();
    return workTask; 
}

现在,如果它是唯一的 await ,你确实可以这样优化它:

public Task ProcessAsync()
{
    Task<string> workTask = SimulateWork();
    return workTask; 
}

但是,它会给您带来完全不同的异常传播行为,这可能会产生一些意想不到的副作用。问题是,现在可能会在调用者的堆栈上抛出异常,这取决于 SimulateWork 的方式。是内部实现的。我发布了 detailed explanation of this behavior . async 通常不会发生这种情况Task/Task<>方法,其中异常存储在返回的 Task 中目的。对于 async void 仍然可能发生方法,但这是一个 different story .

因此,如果您的调用者代码已准备好应对异常传播中的此类差异,那么跳过 async/await 可能是个好主意。无论您在哪里,只需返回一个 Task相反。

另一件事是,如果您想发出一个即发即弃调用。通常,您仍然希望以某种方式跟踪已触发任务的状态,至少出于处理任务异常的原因。我无法想象我真的不在乎任务是否永远不会完成的情况,即使它所做的只是记录日志。

因此,对于“即发即弃”,我通常使用助手 async void将待处理任务存储在某处以供以后观察的方法,例如:

readonly object _syncLock = new Object();
readonly HashSet<Task> _pendingTasks = new HashSet<Task>();

async void QueueTaskAsync(Task task)
{
    // keep failed/cancelled tasks in the list
    // they will be observed outside
    lock (_syncLock)
        _pendingTasks.Add(task);

    try
    {
        await task;
    }
    catch
    {
        // is it not task's exception?
        if (!task.IsCanceled && !task.IsFaulted)
            throw; // re-throw

        // swallow, but do not remove the faulted/cancelled task from _pendingTasks 
        // the error will be observed later, when we process _pendingTasks,
        // e.g.: await Task.WhenAll(_pendingTasks.ToArray())
        return;
    }

    // remove the successfully completed task from the list
    lock (_syncLock)
        _pendingTasks.Remove(task);
}

你可以这样调用它:

public Task ProcessAsync()
{
    QueueTaskAsync(SimulateWork());
}

目标是立即在当前线程的同步上下文中抛出致命异常(例如,内存不足),而任务结果/错误处理被推迟到适当的时候。

关于使用即发即弃任务的有趣讨论here .

关于c# - 等待最后一次时不必要的异步/等待?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23382851/

有关c# - 等待最后一次时不必要的异步/等待?的更多相关文章

  1. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  2. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  3. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  6. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  7. ruby-on-rails - Rake 任务仅调用一次时执行两次 - 2

    我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里

  8. ruby - Hanami link_to 助手只呈现最后一个元素 - 2

    我是HanamiWorld的新人。我已经写了这段代码:moduleWeb::Views::HomeclassIndexincludeWeb::ViewincludeHanami::Helpers::HtmlHelperdeftitlehtml.headerdoh1'Testsearchengine',id:'title'hrdiv(id:'test')dolink_to('Home',"/",class:'mnu_orizontal')link_to('About',"/",class:'mnu_orizontal')endendendendend我在模板上调用了title方法。htm

  9. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  10. ruby - 我怎样才能只写一次 "Text"并同时检查 path_info 是否包含 'A' ? - 2

    -if!request.path_info.include?'A'%{:id=>'A'}"Text"-else"Text"“文本”写了两次。我怎样才能只写一次并同时检查path_info是否包含“A”? 最佳答案 有两种方法可以做到这一点。使用部分,或使用content_forblock:如果“文本”较长,或者是一个重要的子树,您可以将其提取到一个部分。这会使您的代码变干一点。在给出的示例中,这似乎有点矫枉过正。在这种情况下更好的方法是使用content_forblock,如下所示:-if!request.path_info.inc

随机推荐