2015-10-22 4 views
0

Прежде всего, позвольте мне описать поток программы, которую я пишу.Любой способ дождаться завершения всех задач в ActionBlock?

В графическом интерфейсе есть список объектов, и когда пользователь нажимает на него, данные объекта считываются с диска и загружаются. Это может занять около 3-4 секунд.

Предположим, пользователь нетерпелив и нажимает на другой объект, пока первый по-прежнему загружается. Программа загрузит второй объект и в то же время отменит загрузку для первого объекта.

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

Так у меня есть блок действий, как это:

this.loadObjectActionBlock = new ActionBlock<CaseObject>(
    c => this.LoadCaseData(CaseObject), 
    new ExecutionDataflowBlockOptions() 
    { 
     MaxDegreeOfParallelism = 10, 
    }); 

Каждый раз, когда пользователь нажимает на случай объекта, я буду называть:

this.loadObjectActionBlock.Post(CaseObject); 

И CaseObject будет обрабатываться функции Я определил вот так:

private void LoadCaseData(CaseObject caseObject) 
    { 
     caseObject.LoadCaseData();   
    } 

Что мне нужно сделать прямо сейчас, мне нужно подождать пока не будут загружены ВСЕ CaseObjects, чтобы я мог продолжить мой код после этого.

Я попытался определить, когда все случаи обрабатываются путем вызова

if (this.loadObjectActionBlock.InputCount == 0) 
{ 
    this.loadObjectActionBlock.Complete(); 
} 

после caseObject.LoadCaseData();, но это приводит к неожиданным результатам, когда действия нагрузки произойдет слишком быстро, и блок действия говорят не принимать больше входов. Если я правильно понимаю, свойство InputCount рассматривает только количество заданий, оставшихся в очереди.

Так что я хотел бы сделать, это я хотел бы дождаться ActionBlock как:

await this.loadObjectActionBlock.Completion; 

когда все в очереди были полностью обработаны.

Возможно, я не использую ActionBlock так, как он предназначен, поэтому, если есть какие-либо альтернативы, пожалуйста, предложите все, что я мог бы прочитать.

TLDR: Я хотел бы обрабатывать несколько задач (начатых пользователем) одновременно и дождаться завершения всех, а затем выполнить одну задачу.

Заранее спасибо :)

ответ

1

Программа загрузит второй объект и в то же время, отменит загрузку для первого объекта.

Очередь не является подходящим решением для такого поведения, тем более, что блок TPL может быть выполнен только один раз.

Если вы хотите реализовать такое поведение, просто обеспечить маркер отмены наблюдается перед продолжением следующей операции:

private static void ProcessCase(CaseObject caseObject, CancellationToken token) 
{ 
    caseObject.LoadCaseData(); 
    token.ThrowIfCancellationRequested(); 
    ... // Further processing goes here 
} 

Called из потока пользовательского интерфейса, как:

static CancellationTokenSource _cts; 
private static async Task ProcessCaseAsync(CaseObject caseObject) 
{ 
    if (_cts != null) 
    _cts.Cancel(); 
    _cts = new CancellationTokenSource(); 
    await Task.Run(() => ProcessCase(caseObject, _cts.Token)); 
} 
+0

Спасибо за ваш ответ. Бит отмены не является проблемой сейчас, так как я отменяю нагрузку вне метода ProcessCase, и моему файлу actionblock не нужен токен отмены. Я застрял в основном в той части, в которой мне хотелось бы дождаться завершения очереди «ProcessCase» до ее завершения, прежде чем продолжить. Task.WhenAll, вероятно, не подходит для моего случая либо потому, что количество задач не определено, так как они вручную добавляются пользователем. –

+0

@ KurtisAung: Решение, которое я разместил, не требует потока данных TPL, и не нужно ждать завершения всех действий, потому что только последнее действие будет продолжено в строке '... // Дальнейшая обработка'. –

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