使用async/await运行几个无限循环
本文关键字:几个 无限循环 async await 运行 使用 | 更新日期: 2023-09-27 18:27:03
我正在开发基于xamarin和.net 5 async/ewaiting的android messanger应用程序。
在我的应用程序中,我有生产者/消费者模式来处理在无限循环中生成的消息。
例如ReadTcpClientSync生产者:
async Task ReadTcpClientAsync(CancellationToken cancellationToken)
{
cde.Signal();
while (!cancellationToken.IsCancellationRequested)
{
byte[] buffer = await atc.ReadAsync(cancellationToken);
// queue message...
}
}
或SendStatementsAsync使用者,它取消消息并等待WriteAsync
private async Task SendStatementsAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var nextItem = await _outputStatements.Take();
cancellationToken.ThrowIfCancellationRequested();
// misc ...
await atc.WriteAsync(call.Serialize());
}
}
一些消费者只是在等待Take呼叫
var update = await _inputUpdateStatements.Take();
这种结构在测试中效果很好,但有一种方法我认为我犯了一个巨大的错误。该方法旨在运行整个客户端后端,同时启动3个pro/conwhile(true)循环。
在这里:
public async Task RunAsync()
{
_isRunning = true;
_progress.ProgressChanged += progress_ProgressChanged;
await InitMTProto(_scheme).ConfigureAwait(false); // init smth...
// various init stuf...
await atc.ConnectAsync().ConfigureAwait(false); // open connection async
// IS IT WRONG?
try
{
await Task.WhenAny(SendStatementsAsync(_cts.Token),
ReadTcpClientAsync(_cts.Token),
ProcessUpdateAsync(_cts.Token, _progress)).ConfigureAwait(false);
}
catch (OperationCanceledException oce)
{
}
catch (Exception ex)
{
}
}
暂时忘记android,想想UI上下文中的任何UI(WinForm、WPF等)OnCreate方法来调用RunAsync
protected async override void OnCreate(Bundle bundle)
{
// start RA
await client.RunAsync()
// never gets here - BAD, but nonblock UI thread - good
Debug.WriteLine("nevar");
}
因此,正如您所看到的,存在一个问题。在RunAsync等待调用后,我不能做任何事情,因为它永远不会从Task.WenAny(…)返回。我需要在那里执行状态检查,但我需要启动这个pro/cons方法,因为我的检查等待它的ManualResetEvent:
if (!cde.Wait(15000))
{
throw new TimeoutException("Init too long");
}
此外,我的检查也是异步的,它就像一个魅力:)
public async Task<TLCombinatorInstance> PerformRpcCall(string combinatorName, params object[] pars)
{
// wait for init on cde ...
// prepare call ...
// Produce
ProduceOutput(call);
// wait for answer
return await _inputRpcAnswersStatements.Take();
}
我认为我应该使用另一种方法来启动这个无限循环,但我一直都有异步任务方法,所以我真的不知道该怎么办。请帮忙吗?
好吧,经过大量阅读(没有发现任何内容)和@svick的建议,我决定将这些方法作为单独的Task.Run调用,而不使用"wait"。麻生太郎决定在线程池中运行它。
我的最终代码是:
try
{
/*await Task.WhenAny(SendStatementsAsync(_cts.Token),
ReadTcpClientAsync(_cts.Token),
ProcessUpdateAsync(_cts.Token, _progress)).ConfigureAwait(false);*/
Task.Run(() => SendStatementsAsync(_cts.Token)).ConfigureAwait(false);
Task.Run(() => ReadTcpClientAsync(_cts.Token)).ConfigureAwait(false);
Task.Run(() => ProcessUpdateAsync(_cts.Token, _progress)).ConfigureAwait(false);
Trace.WriteLineIf(clientSwitch.TraceInfo, "Worker threads started", "[Client.RunAsync]");
}
一切如预期般顺利。。我不确定它会在异常处理中引起什么问题,因为我知道它们会丢失
当然,这样的呼叫会产生警告
由于未等待此调用,因此当前方法的执行在呼叫完成之前继续。考虑应用"等待"操作员查看呼叫结果。
通过这种方式可以很容易地抑制
// just save task into variable
var send = Task.Run(() => SendStatementsAsync(_cts.Token)).ConfigureAwait(false);
此外,如果有人知道更好的解决方案,我将非常感激听到它。