2013-08-10 2 views
3

Я разрабатываю приложение Android-мессенджера на основе xamarin и .net 5 async/ждет.Запуск нескольких бесконечных циклов с асинхронным/ожиданием

В моем приложении у меня есть шаблон производителя/потребителя для обработки сообщений, которые производятся на бесконечных циклах.

, например ReadTcpClientAsync производителя:

async Task ReadTcpClientAsync(CancellationToken cancellationToken) 
{ 
    cde.Signal(); 
    while (!cancellationToken.IsCancellationRequested) 
    { 
     byte[] buffer = await atc.ReadAsync(cancellationToken); 
     // queue message... 
    } 
} 

или SendStatementsAsync потребителя, который DEQUE сообщений и ожидает 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(); 

это строительно-монтажных работ довольно хорошо на тестах, но есть один метод wh потому что я думаю, что совершил огромную ошибку. Этот метод предназначен для запуска всего клиентского бэкэнд, начиная с 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) 
    { 

    } 
} 

Забудьте о андроида на данный момент, думаю, любой пользовательский интерфейс (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.WhenAny (...). И мне нужно выполнить проверку состояния, но мне нужно это про/минусы методы, созданные, потому что мой чек ждать на 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(); 
} 

Я думаю, что я должен использовать другой подход для запуска этой бесконечной петли, но я уже ASync Методы ЗАДАЧИ всего пути - так что я действительно не знаю, что делать. Любая помощь, пожалуйста?

+0

Посмотрите на BlockingCollection – Paparazzi

+0

Просто не 'await'' RunAsync()'? – svick

+0

@Blam У меня есть собственная реализация IProducerConsumer, и он работает очень хорошо, мне не нужен другой. – xakz

ответ

1

Хорошо, после многого чтения (ничего не найдено) и совета @ svick я решил назвать эти методы без «ожидания» в качестве отдельной Task.Run. Aso я решил запустить его в ThreadPool.

Мой окончательный код:

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); 

Кроме того, если кто-нибудь знает лучшее решение я буду благодарен услышать.

Смежные вопросы