我正在开发一款基于Xamarin和.NET 5 Async/Await的Android通讯应用。
在我的应用中,我采用了生产者/消费者模式来处理消息,该模式是基于无限循环实现的。
例如,ReadTcpClientAsync生产者:
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());
}
}
一些消费者只是依赖于接听电话。
var update = await _inputUpdateStatements.Take();
这个构造在测试中运行得很好,但是有一个方法我认为犯了一个巨大的错误。
这个方法旨在同时启动3个pro/con while (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(WinForm,WPF等)的OnCreate方法在UI上下文中调用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 await 调用之后,我无法执行任何操作,因为它永远不会从 Task.WhenAny(...) 中返回。我需要在那里执行状态检查,但我需要启动此 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();
}
我认为我应该使用另一种方法来启动这个无限循环,但是我已经一路使用了异步任务方法 - 所以我真的不知道该怎么做了。 请帮忙吗?
await
来调用RunAsync()
吗? - svick