2016-12-01 7 views
3

私は4つの非同期タスク(内部的にサードパーティのWebサービスを呼び出す)を呼び出す必要があるC#アプリケーションを用意しました。 各タスクは、成功または失敗に応じてブール値true/falseを返します。複数のタスクを呼び出す

これらの4つのタスクのいずれかがtrueを返すと、PostProcessing()という別のメソッドを呼び出す必要があります。 #2メソッド呼び出しがtrueを返す場合は、処理を中止してPostProcessing()メソッドを呼び出す必要があります。

すべてのタスクがfalseを返す場合、私はPostProcessing()を呼びたくありません。

このアプローチを実装する最良の方法は何ですか?Task.ContinueWith()ですか?

ありがとうございました。

+1

'タスクを。いつ誰もがすぐに気になるが、それは "1つが本当に戻る"という部分を考慮に入れておらず、他の仕事を停止しない。これはXY問題になる可能性があります。解決しようとしている実際の問題を記述することはできますか? – BradleyDotNET

+0

4人すべてが 'false'を返すとどうなりますか? – Enigmativity

+0

こんにちはEnigmativity、私は今質問を更新しました。ありがとう。 –

答えて

3

私はこれに対してMicrosoftのReactive Framework(Rx)を使用します。

私はあなたが作業しているメソッドのシグネチャが、これらがあると仮定しますと起動するには:

public async Task<bool> WebService1() 
public async Task<bool> WebService2() 
public async Task<bool> WebService3() 
public async Task<bool> WebService4() 
public void PostProcessing() 

今、あなたはこのように、この使用に受信を設定することができます。

var webservices = new Func<Task<bool>>[] 
{ 
    WebService1, WebService2, WebService3, WebService4, 
}; 

IObservable<bool> query = 
    webservices 
     .ToObservable() 
     .SelectMany(ws => Observable.FromAsync(ws)) 
     .Where(b => b == true) 
     .Take(1); 

IDisposable subscription = query.Subscribe(b => PostProcessing()); 

この正常に4つのWeb非同期サービス(Observable.FromAsync(ws))をすべて非同期に.ToObservable().SelectMany(...)と呼び出し、結果をフィルタリングしてtrue.Where(b => b == true))にのみフィルタリングします。最終的には1つの結果しか得られません.Take(1)

次に、1つの結果(trueである必要があります)が発生した場合は、PostProcessingを呼び出します。

Webサービスが返される前に中止する必要がある場合は、いつでもsubscription.Dispose()に電話することができます。

シンプルです。

+0

非常に巧妙、私は調査したいリアクティブフレームワーク – BradleyDotNET

+0

@BradleyDotNET - Rxを使い始めると、再びTPLに触れることは決してありません。それはあまりにも制限的です。 :-) – Enigmativity

+0

Thanks @ Enigmativity.Just to ...このアプローチを使用すると、4つのメソッドがすべて同時に実行され、メソッド2がtrueを返した場合、他のメソッドがtrueまたはfalseを返すかどうかは気になりませんこれらの3つの方法の処理をすべて中止しますか?この理解は間違っていませんか? –

-1

私は自分の携帯電話にいるので、コードを書くのは難しいでしょう。しかし、私の理解から、取り消しトークンはあなたが望むものです。ここをクリックしてくださいhttps://msdn.microsoft.com/en-us/library/system.threading.cancellationtoken(v=vs.110).aspx

あなたはあなたのメソッドを呼び出すキャンセル要求のコールバックを登録することができます。例を見てくださいhttps://msdn.microsoft.com/en-us/library/ee191554(v=vs.110).aspx

+0

これは、彼がトークンを聞いている場合にのみ役立ちます。最初のものを検出しても真実に戻っても解決しません。 – BradleyDotNET

+0

@BradleyDotNET –

+0

と呼ばれる取り消しトークンを使用してデリゲートを登録することができます。 – BradleyDotNET

1

個人的には、おそらくReactive Extensions(@Enigmativityなど)を使用しています。 Reactive Extensionsの使用を避けたい場合は、Task.WhenAnyとwhileループを組み合わせることができます。私がこのルートに行くなら、私は物事をきれいに保つために静的な方法を作ります。だからこのようなもの:

public static class TaskExtensions 
{ 
    public static async Task<Task<TResult>> WhenAnyWithPredicate<TResult>(Func<Task<TResult>, bool> predicate, params Task<TResult>[] tasks) 
    { 
     if (tasks == null) 
     { 
      throw new ArgumentNullException(); 
     } 

     if (tasks.Length == 0) 
     { 
      return null;  
     } 

     // Make a safe copy (in case the original array is modified while we are awaiting). 
     tasks = tasks.ToArray(); 

     // Await the first task. 
     var result = await Task.WhenAny(tasks); 

     // Test the task and await the next task if necessary. 
     while (tasks.Length > 0 && !predicate(result)) 
     { 
      tasks = tasks.Where(x => x != result).ToArray(); 
      if (tasks.Length == 0) 
      { 
       result = null; 
      } 
      else 
      { 
       result = await Task.WhenAny(tasks); 
      } 
     } 

     // Return the result. 
     return result; 
    } 
} 

このように使用します。

CancellationTokenSource cts = new CancellationTokenSource(); 

// Start your four tasks. 
var tasks = new Task<bool>[] 
{ 
    CreateTask1WithCancellationToken(cts.Token), 
    CreateTask2WithCancellationToken(cts.Token), 
    CreateTask3WithCancellationToken(cts.Token), 
    CreateTask4WithCancellationToken(cts.Token), 
} 

// Wait for the first task with a result of 'true' to complete. 
var result = await TaskExtensions.WhenAnyWithPredicate(x => x.Status == TaskStatus.RanToCompletion && x.Result, tasks); 

// Cancel the remaining tasks (if any). 
cts.Cancel(); 

// If you have a nonnull task then success! 
if (result != null) 
{ 
    PostProcessing(); 
} 
0

私はこのようなものだろう:

var cancellationSource = new CancellationTokenSource(); 

// Start the tasks 
var tasks = new List<Task<bool>> 
{ 
    WebService(cancellationSource.Token), 
    WebService(cancellationSource.Token), 
    WebService(cancellationSource.Token), 
    WebService(cancellationSource.Token) 
}; 

// Wait until first task returns true 
bool success = false; 
while (!success && tasks.Any()) 
{ 
    var completedTask = await Task.WhenAny(tasks); 
    try 
    { 
     // It either completed or failed, try to get the result 
     success = await completedTask; 
    } 
    catch (Exception ex) 
    { 
     // ignore or log exception 
    } 
    tasks.Remove(completedTask); 
} 

// Cancel remaining tasks 
cancellationSource.Cancel(); 

// Ensure all tasks have completed to avoid unobserved exceptions 
if (tasks.Any()) 
{ 
    try 
    {   
     await Task.WhenAll(tasks); 
    } 
    catch (Exception ex) 
    { 
     // ignore or log exception 
    } 
} 

if (success) 
{ 
    PostProcessing(); 
} 

としてEnigmativityのソリューションとして空想が、簡単ではありません;)

関連する問題