这不是"如何在没有等待的情况下安全地调用C#中的异步方法"的副本.
我如何很好地抑制以下警告?
警告CS4014:由于未等待此调用,因此在完成调用之前,将继续执行当前方法.考虑将'await'运算符应用于调用的结果.
一个简单的例子:
static async Task WorkAsync()
{
await Task.Delay(1000);
Console.WriteLine("Done!");
}
static async Task StartWorkAsync()
{
WorkAsync(); // I want fire-and-forget
// more unrelated async/await stuff here, e.g.:
// ...
await Task.Delay(2000);
}
Run Code Online (Sandbox Code Playgroud)
我尝试过但不喜欢的事情:
static async Task StartWorkAsync()
{
#pragma warning disable 4014
WorkAsync(); // I want fire-and-forget here
#pragma warning restore 4014
// ...
}
static async Task StartWorkAsync()
{
var ignoreMe = WorkAsync(); // I want fire-and-forget here
// ...
}
Run Code Online (Sandbox Code Playgroud)
更新后,由于原始接受的答案 …
刚刚获得VS2012并试图获得处理async
.
假设我有一个方法可以从阻塞源中获取一些值.我不希望方法的调用者阻止.我可以编写方法来获取在值到达时调用的回调,但由于我使用的是C#5,我决定使方法异步,因此调用者不必处理回调:
// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
return Task.Factory.StartNew(() => {
Console.Write(prompt);
return Console.ReadLine();
});
}
Run Code Online (Sandbox Code Playgroud)
这是一个调用它的示例方法.如果PromptForStringAsync
不是异步,则此方法需要在回调中嵌套回调.使用异步,我可以用这种非常自然的方式编写我的方法:
public static async Task GetNameAsync()
{
string firstname = await PromptForStringAsync("Enter your first name: ");
Console.WriteLine("Welcome {0}.", firstname);
string lastname = await PromptForStringAsync("Enter your last name: ");
Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.问题是当我调用 GetNameAsync时:
public static void DoStuff()
{
GetNameAsync();
MainWorkOfApplicationIDontWantBlocked();
}
Run Code Online (Sandbox Code Playgroud)
重点GetNameAsync
是它是异步的.我不 …
考虑这个例子:
var task = DoSomething()
bool ready = await DoSomethingElse();
if (!ready)
return null;
var value = await DoThirdThing(); // depends on DoSomethingElse
return value + await task;
Run Code Online (Sandbox Code Playgroud)
DoSomething
做一些可能需要一段时间的非常重要的工作,因此我们首先开始它.
与此同时,我们检查我们是否准备就绪,DoSomethingElse
如果没有,我们会提前退出.
我们DoThirdThing
只有在我们这样做时才会打电话ready
,因为宇宙可能会爆炸.
我们不能用Task.WhenAll
作为DoThirdThing
依赖DoSomethingElse
,我们也不想等待DoSomething
,因为我们希望尽可能地其他两种方法同时调用.
问题:发生什么task
,如果我们不能ready
和退出早?
它抛出的任何异常会被重新抛出SynchronizationContext
吗?
如果task
正常完成会有问题吗,因为没有人消耗它的价值?
后续行动:有没有一种简洁的方法可以确保task
等待?
我们可以简单地说,await task
如果我们不是ready
,但如果有50个退出条件,这将是非常繁琐的.
可以使用finally
块来await task
重新抛出潜在的异常吗?如果task
正常完成,将在finally
块中再次等待,但这不应该导致任何问题?
我正在使用同步apis和线程池的tcp服务器上看起来像这样:
TcpListener listener;
void Serve(){
while(true){
var client = listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(this.HandleConnection, client);
//Or alternatively new Thread(HandleConnection).Start(client)
}
}
Run Code Online (Sandbox Code Playgroud)
假设我的目标是在资源使用率最低的情况下处理尽可能多的并发连接,这似乎很快就会受到可用线程数量的限制.我怀疑通过使用非阻塞任务apis,我将能够用更少的资源处理更多.
我最初的印象是这样的:
async Task Serve(){
while(true){
var client = await listener.AcceptTcpClientAsync();
HandleConnectionAsync(client); //fire and forget?
}
}
Run Code Online (Sandbox Code Playgroud)
但令我印象深刻的是,这可能会导致瓶颈.也许HandleConnectionAsync需要花费非常长的时间才能达到第一次等待,并且将阻止主接受循环继续进行.这只会使用一个线程,还是运行时会在多个线程上神奇地运行它看起来合适的东西?
有没有办法结合这两种方法,以便我的服务器将使用它所需的线程数量来确定正在运行的任务的数量,但是它不会在IO操作上不必要地阻塞线程?
在这样的情况下,是否存在最大化吞吐量的惯用方法?
我最近一直在处理异步等待(阅读包括Stephen和Jon最后两章在内的所有可能的文章),但我得出结论,我不知道它是否100%正确. - 因此我的问题.
由于 async
只允许单词等待出现,我将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 ...
}
Run Code Online (Sandbox Code Playgroud)
当线程到达时await workTask;
,将方法拆分为2个部分.所以在SimulateWork
完成之后 - 方法的继续:AKA://do something with st
- 被执行.
一切都好
但是,如果方法是:
public async Task ProcessAsync()
{
Task<string> workTask = SimulateWork();
await workTask; //i …
Run Code Online (Sandbox Code Playgroud) 我认为异步方法应该像普通方法一样,直到他们到达等待.
为什么这不会抛出异常?
有没有办法在没有等待的情况下抛出异常?
using System;
using System.Threading.Tasks;
public class Test
{
public static void Main()
{
var t = new Test();
t.Helper();
}
public async Task Helper()
{
throw new Exception();
}
}
Run Code Online (Sandbox Code Playgroud) 我见过的一个常见问题是管理任务中未处理的异常.它们不会导致崩溃,它们会无声地发生,我甚至无法在任务失败时触发事件!我已经看到用户开出自定义类和处理这个的东西,我的问题是,是否有一种"标准"的微软方式来处理这个问题?
为了举例,我制作了这个简单的控制台应用程序(.NET 4.5.1)来演示这个问题.是否可以修改这些任务以便可以异步执行这些任务,但在遇到未处理的异常时调用"handler"?或者至少崩溃?我认为这就是UnobservedTaskException应该做的事情.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += Handler;
AppDomain.CurrentDomain.UnhandledException += Handler;
Task.Run(() => { throw new ApplicationException("I'll throw an unhandled exception"); });
Task.Factory.StartNew(() => { throw new ApplicationException("I'll throw an unhandled exception too"); });
System.Threading.Thread.Sleep(2000);
Console.WriteLine("I think everything is just peachy!");
System.Threading.Thread.Sleep(10000);
}
private static void Handler(Object sender, EventArgs e)
{
Console.WriteLine("I'm so lonely, won't anyone call me?");
}
}
} …
Run Code Online (Sandbox Code Playgroud) 以下代码按我的意愿工作,但会引发警告:
Warning 1 Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
是否有一个替代方案Task.Run()
将以一种简洁的方式启动这个线程?
/// <summary>
/// StartSubscriptionsAsync must be called if you want subscription change notifications.
/// This starts the subscription engine. We always create one subscription for
/// Home DisplayName to start (but ignore any updates).
/// </summary>
public async Task StartSubscriptionsAsync(){
await _subscriptionClient.ConnectAsync(Host, Port);
// Generates a …
Run Code Online (Sandbox Code Playgroud) 我有一个WebApi控制器,其中一个部分是向一组用户发送电子邮件.
[HttpPost]
[Authorize]
[Route("{id}/Do")]
public async Task<HttpResponseMessage> Post(int id, Model model)
...
await _emailService.SendAsync(message);
...
Run Code Online (Sandbox Code Playgroud)
现在发送电子邮件的方法(SendGrid)
public override async Task SendAsync(MailMessage message)
{
var client =
new SmtpClient(SendGridServerName, SendGridServerPort)
{
Port = SendGridServerPort,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false
};
var credentials = new NetworkCredential(SendGridUserName, SendGridPassword);
client.EnableSsl = true;
client.Credentials = credentials;
message.From = new MailAddress(FromAddress);
await client.SendMailAsync(message);
}
Run Code Online (Sandbox Code Playgroud)
一切正常,但速度很慢.我期待它快,但await _emailService.SendAsync(message);
看起来并不是异步.它停在那里一段时间.
有任何想法吗?
谢谢
我遇到了以下有关何时何地使用的文章ConfigureAwait(false)
,但无法得到答案。
您不需要 ConfigureAwait(false),但仍可在库和 UI 应用程序中使用它。(例如 Xamarin、WinForms 等)
https://blog.stephencleary.com/2017/03/aspnetcore-synchronization-context.html
此链接说相反的答案
为所有服务器端代码调用 ConfigureAwait 的最佳实践
我的问题:
场景 1:下面的代码作为后台服务运行。
我的问题:ConfigureAwait(false)
无论何时await
都需要像下面的 A 和 B 一样使用:
[Service(Name = "com.MainApplicationService", Label = "Main Application Service", Exported = false)]
public class MainApplicationService : Android.App.Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
await InitAsync().ConfigureAwait(false); //line A
Task.Run(async () => await …
Run Code Online (Sandbox Code Playgroud) c# task-parallel-library xamarin.android async-await xamarin
这是场景:在我的WPF应用程序中,我希望始终保持循环运行以执行各种操作.我想到了这种模式:
void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
SomeProcessAsync(); //throw away task
}
async Task SomeProcessAsync()
{
while (true)
{
DoSomething();
await Task.Delay(1000);
}
}
Run Code Online (Sandbox Code Playgroud)
由于返回值未使用,该调用会触发警告.沉默警告的最简洁方法是什么?
#pragma warning disable 4014
AddItemsAsync(); //throw away task
#pragma warning restore 4014
Run Code Online (Sandbox Code Playgroud)
这有效,但看起来很讨厌!
顺便说一句,我也可以使用计时器,但我喜欢这个循环的简单性.
我有一个服务器应用程序来接受来自一组大约 10000 个客户端(实际上是具有 GPRS 接口的现场设备)的 TCP 连接。
接受连接的部分是这样的:
public async System.Threading.Tasks.Task AcceptConnections()
{
_listenerProxy.StartListen();
var taskList = new List<System.Threading.Tasks.Task>();
var application = _configManager.Configuration.GetSection("application");
var maxTasks = int.Parse(application["MaxTasksPerListener"]);
while (true)
{
if (taskList.Count > maxTasks)
{
_logger.Info($"Waiting for handling task to be completed {_listenerProxy.Port}.");
await System.Threading.Tasks.Task.WhenAny(taskList.ToArray()).ConfigureAwait(false);
taskList.RemoveAll(t => t.IsCompleted); // at least one task affected, but maybe more
}
_logger.Info($"Waiting for client to be accepted on port {_listenerProxy.Port}.");
(var readStream, var writeStream, var sourceIP, var sourcePort) = await _listenerProxy.AcceptClient().ConfigureAwait(false);
_logger.Info($"Client accepted …
Run Code Online (Sandbox Code Playgroud) c# ×12
async-await ×10
asynchronous ×3
.net ×2
tcplistener ×2
c#-5.0 ×1
email ×1
sendgrid ×1
sockets ×1
tcpclient ×1
threadpool ×1
xamarin ×1