如何在不等待的情况下安全地在C#中调用异步方法

本文探讨了在C#中如何在不等待的情况下安全地调用异步方法,解决不等待可能引发的异常问题。讨论中提到了在ASP.NET Web API环境中,直接等待可能增加响应时间,建议通过Task.Run或其他方法处理异常,同时警告此类操作不适合关键业务操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文翻译自:How to safely call an async method in C# without await

I have an async method which returns no data: 我有一个不返回任何数据的async方法:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

I'm calling this from another method which returns some data: 我从另一个返回一些数据的方法中调用此方法:

public string GetStringData()
{
    MyAsyncMethod(); // this generates a warning and swallows exceptions
    return "hello world";
}

Calling MyAsyncMethod() without awaiting it causes a " Because this call is not awaited, the current method continues to run before the call is completed " warning in visual studio. MyAsyncMethod()调用MyAsyncMethod()而不等待它会导致“ 因为未等待此调用,因此当前方法将在调用完成之前继续运行 ”警告。 On the page for that warning it states: 在该警告的页面上,它指出:

You should consider suppressing the warning only if you're sure that you don't want to wait for the asynchronous call to complete and that the called method won't raise any exceptions . 仅当您确定不想等待异步调用完成并且被调用的方法不会引发任何异常时 ,才应考虑禁止显示警告。

I'm sure I don't want to wait for the call to complete; 我确定我不想等待通话结束。 I don't need to or have the time to. 我不需要或没有时间。 But the call might raise exceptions. 但是通话可能会引发异常。

I've stumbled into this problem a few times and I'm sure it's a common problem which must have a common solution. 我已经几次遇到这个问题,并且我确定这是一个常见的问题,必须有一个通用的解决方案。

How do I safely call an async method without awaiting the result? 如何安全地调用异步方法而不等待结果?

Update: 更新:

For people suggesting that I just await the result, this is code that is responding to a web request on our web service (ASP.NET Web API). 对于建议我只是等待结果的人,这是响应我们Web服务(ASP.NET Web API)上的Web请求的代码。 Awaiting in a UI context keeps the UI thread free, but awaiting in a web request call will wait for the Task to finish before responding to the request, thereby increasing response times with no reason. 在UI上下文中等待将保持UI线程空闲,但是在Web请求调用中等待将等待Task完成,然后再响应请求,从而无故增加了响应时间。


#1楼

参考:https://stackoom.com/question/138dm/如何在不等待的情况下安全地在C-中调用异步方法


#2楼

I guess the question arises, why would you need to do this? 我想这个问题出现了,为什么您需要这样做? The reason for async in C# 5.0 is so you can await a result. 在C#5.0中进行async的原因是,您可以等待结果。 This method is not actually asynchronous, but simply called at a time so as not to interfere too much with the current thread. 此方法实际上不是异步的,而是一次调用一次,以免对当前线程造成过多干扰。

Perhaps it may be better to start a thread and leave it to finish on its own. 也许最好启动一个线程并让它自己完成。


#3楼

You should first consider making GetStringData an async method and have it await the task returned from MyAsyncMethod . 您应该首先考虑使GetStringData成为async方法,并使其await MyAsyncMethod返回的任务。

If you're absolutely sure that you don't need to handle exceptions from MyAsyncMethod or know when it completes, then you can do this: 如果您完全确定不需要处理MyAsyncMethod异常知道它何时完成,则可以执行以下操作:

public string GetStringData()
{
  var _ = MyAsyncMethod();
  return "hello world";
}

BTW, this is not a "common problem". 顺便说一句,这不是一个“常见问题”。 It's very rare to want to execute some code and not care whether it completes and not care whether it completes successfully. 这是非常罕见的要执行一些代码,并不在乎它是否完成不在乎是否成功完成。

Update: 更新:

Since you're on ASP.NET and wanting to return early, you may find my blog post on the subject useful . 由于您使用的是ASP.NET并希望早日返回,因此您可能会发现关于该主题的博客文章很有用 However, ASP.NET was not designed for this, and there's no guarantee that your code will run after the response is returned. 但是,ASP.NET并非为此设计的,因此不能保证您的代码将在返回响应后运行。 ASP.NET will do its best to let it run, but it can't guarantee it. ASP.NET将尽其所能使其运行,但不能保证。

So, this is a fine solution for something simple like tossing an event into a log where it doesn't really matter if you lose a few here and there. 所以,这是一些简单的罚款解决方案一样折腾的事件记录到日志:如果你失去了几这里和那里它其实并不重要。 It's not a good solution for any kind of business-critical operations. 对于任何类型的关键业务操作来说,这都不是一个好的解决方案。 In those situations, you must adopt a more complex architecture, with a persistent way to save the operations (eg, Azure Queues, MSMQ) and a separate background process (eg, Azure Worker Role, Win32 Service) to process them. 在这种情况下,您必须采用更复杂的体系结构,并采用一种持久的方式来保存操作(例如,Azure队列,MSMQ),并使用单独的后台进程(例如,Azure Worker角色,Win32 Service)来处理它们。


#4楼

If you want to get the exception "asynchronously", you could do: 如果要“异步”获取异常,则可以执行以下操作:

  MyAsyncMethod().
    ContinueWith(t => Console.WriteLine(t.Exception),
        TaskContinuationOptions.OnlyOnFaulted);

This will allow you to deal with an exception on a thread other than the "main" thread. 这将使您可以处理“主”线程以外的线程上的异常。 This means you don't have to "wait" for the call to MyAsyncMethod() from the thread that calls MyAsyncMethod ; 这意味着您不必“等待”来自调用MyAsyncMethod的线程对MyAsyncMethod()的调用; but, still allows you to do something with an exception--but only if an exception occurs. 但是,仍然允许您执行例外操作-但仅当发生例外时。

Update: 更新:

technically, you could do something similar with await : 从技术上讲,您可以使用await做类似的事情:

try
{
    await MyAsyncMethod().ConfigureAwait(false);
}
catch (Exception ex)
{
    Trace.WriteLine(ex);
}

...which would be useful if you needed to specifically use try / catch (or using ) but I find the ContinueWith to be a little more explicit because you have to know what ConfigureAwait(false) means. ...如果您需要专门使用try / catch (或using ),这将很有using但是我发现ContinueWith更加明确,因为您必须知道ConfigureAwait(false)含义。


#5楼

The answer by Peter Ritchie was what I wanted, and Stephen Cleary's article about returning early in ASP.NET was very helpful. Peter Ritchie的答案是我想要的, Stephen Cleary的有关在ASP.NET中尽早返回的文章非常有帮助。

As a more general problem however (not specific to an ASP.NET context) the following Console application demonstrates the usage and behavior of Peter's answer using Task.ContinueWith(...) 但是,作为一个更普遍的问题(不是特定于ASP.NET上下文),以下控制台应用程序使用Task.ContinueWith(...)演示了彼得答案的用法和行为。

static void Main(string[] args)
{
  try
  {
    // output "hello world" as method returns early
    Console.WriteLine(GetStringData());
  }
  catch
  {
    // Exception is NOT caught here
  }
  Console.ReadLine();
}

public static string GetStringData()
{
  MyAsyncMethod().ContinueWith(OnMyAsyncMethodFailed, TaskContinuationOptions.OnlyOnFaulted);
  return "hello world";
}

public static async Task MyAsyncMethod()
{
  await Task.Run(() => { throw new Exception("thrown on background thread"); });
}

public static void OnMyAsyncMethodFailed(Task task)
{
  Exception ex = task.Exception;
  // Deal with exceptions here however you want
}

GetStringData() returns early without awaiting MyAsyncMethod() and exceptions thrown in MyAsyncMethod() are dealt with in OnMyAsyncMethodFailed(Task task) and not in the try / catch around GetStringData() GetStringData()在不等待MyAsyncMethod()情况下MyAsyncMethod()返回,并且MyAsyncMethod()中引发的异常在OnMyAsyncMethodFailed(Task task)中处理,而不是try / catch GetStringData()


#6楼

I end up with this solution : 我最终得到了这个解决方案:

public async Task MyAsyncMethod()
{
    // do some stuff async, don't return any data
}

public string GetStringData()
{
    // Run async, no warning, exception are catched
    RunAsync(MyAsyncMethod()); 
    return "hello world";
}

private void RunAsync(Task task)
{
    task.ContinueWith(t =>
    {
        ILog log = ServiceLocator.Current.GetInstance<ILog>();
        log.Error("Unexpected Error", t.Exception);

    }, TaskContinuationOptions.OnlyOnFaulted);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值