我是 C#
s await/async
的新手,目前正在玩一下 .
在我的场景中,我有一个简单的客户端对象,它具有 WebRequest
属性 . 客户端应定期发送 WebRequest
RequestStream
上的活动消息 . 这是client-object的构造函数:
public Client()
{
_webRequest = WebRequest.Create("some url");
_webRequest.Method = "POST";
IsRunning = true;
// --> how to start the 'async' method (see below)
}
和async alive-sender方法
private async void SendAliveMessageAsync()
{
const string keepAliveMessage = "{\"message\": {\"type\": \"keepalive\"}}";
var seconds = 0;
while (IsRunning)
{
if (seconds % 10 == 0)
{
await new StreamWriter(_webRequest.GetRequestStream()).WriteLineAsync(keepAliveMessage);
}
await Task.Delay(1000);
seconds++;
}
}
该方法应该如何开始?
new Thread(SendAliveMessageAsync).Start();
要么
Task.Run(SendAliveMessageAsync); //将返回类型更改为Task
要么
await SendAliveMessageAsync(); //失败,因为构造函数不是异步的
我的问题更多是关于我个人对_2680320的理解,我想在某些方面可能是错的 .
第三种选择是投掷
The 'await' operator can only be used in a method or lambda marked with the 'async' modifier
5 回答
我投票赞成“以上都不是” . :)
"Fire and forget"是一个难以正确处理的方案 . 特别是,错误处理总是有问题的 . 在这种情况下,
async void
可能会让您感到惊讶 .如果我不是立即执行任务,我更愿意明确保存任务:
这至少允许
Client
的使用者检测并从SendAliveMessageAsync
方法抛出的异常中恢复 .另外,这个模式几乎等同于我的"asynchronous initialization" pattern .
编辑为先前的答案是错误的:
因为它在构造函数中,我认为你必须为它启动一个新的线程 . 我个人会这样做
由于它是 fire and forget 操作,您应该使用它来启动它
请注意
await
不会启动新的Task
. 等待Task
完成只是语法糖 .使用
Task.Run
启动新线程 .所以在
SendAliveMessageAsync
内你应该开始一个新的任务:这里's an option since you can' t从构造函数中调用
await
.我建议使用微软的Reactive Framework(NuGet“Rx-Main”) .
代码如下所示:
此代码处理所需的所有线程并正确处理
StreamWriter
.每当你想要停止保持活动时,只需致电
_subscription.Dispose()
.在您的代码中,不需要使用async / await,只需设置一个新线程来执行长操作 .
使用
Task.Factory.StartNew(SendAliveMessage, TaskCreationOptions.LongRunning)
执行操作 .如果你真的想使用async / await模式,只需在构造函数中调用它而不使用await修饰符并忘记它 .
我认为设置一个长时间运行的线程或使用async / await模式并不是一个好主意 . 定时器可能更适合这种情况 .