2017-12-18 13 views
1

私は現在、データベース内で「プロセスの待機中」としているリクエストごとにタスクを作成するサービスを作成しています。辞書のTask.WhenAnyの使用

プロセスが長くなる可能性があります。トークンを使用してタスクを取り消したい場合は、タスクをキャンセルする必要がある場合にループするたびにサービスをチェックします。したがって、タスクにリンクされたリクエストのIDを保存する必要があります。私は、次のように辞書で私の静的クラスを持っていることについて考えていた

:それは存在してより良い解決策だが、それはまだ働い1は、私が思う場合、私は知らない

public static Dictionary<Int32, Task<Int32>> _tasks = new Dictionary<int, Task<int>>(); 

今、私はTask.WhenAny(..)をして、それらのいずれかが終了した時を知りたいです。問題は、Task.WhenAny(..)は配列を受け入れますが、辞書は受け入れないことです。私は辞書をWhenAnyに渡すことについて何も見ていませんでした。そして、私がワークフローの各キーポイントの解決策を取りたいと思っていた非常に長いプロセス全体を開始する前に、私は辞書の値のリストを得ることができたかもしれないが、おそらく私はIDのリンクを緩めるだろう。だから私は本当に何をすべきか分からないのですか?

解決策はありますか?私は自分自身の「WhenAny」を再現したくないし、可能かどうかわからないが、すべての行の状態を解析できると思う。しかし、それが唯一の選択肢なら、私はそうするでしょう。

このようにリクエストのIDを格納するのは良い方法ではなく、この場合私は他の提案にも公開しています。


EDIT:CODE ACORDING TOは、私が働いているようだ、このコードを使用して終了し に答えます。今はファイル作成だけでなく、もっと複雑な作業でテストします!あなただけ使用することができるはずですので、:)

public static class Worker 
{ 
    public static List<Task<Int32>> m_tasks = new List<Task<Int32>>(); 
    public static Dictionary<Int32, CancellationTokenSource> m_cancellationTokenSources = new Dictionary<int, CancellationTokenSource>(); 
    public static Int32 _testId = 1; 
    public static void run() 
    { 
     //Clean 
     Cleaner.CleanUploads(); 
     Cleaner.CleanDownloads(); 
     #region thread watching 
     if (m_tasks.Count > 0) 
     { 
      #region thread must be cancel 
      //Cancel thread 
      List<Task<Int32>> _removeTemp = new List<Task<Int32>>(); 
      foreach (Task<Int32> _task in m_tasks) 
      { 
       if (DbWorker.mustBeCancel((Int32)_task.AsyncState)) 
       { 
        m_cancellationTokenSources[(Int32)_task.AsyncState].Cancel(); 
        //Cancellation actions 

        //task must be remove 
        _removeTemp.Add(_task); 
       } 
      } 
      foreach(Task<Int32> _taskToRemove in _removeTemp) 
      { 
       m_tasks.Remove(_taskToRemove); 
      } 
      #endregion 
      #region Conversion lookup 
      // Get conversion if any 

      // Create task 
      CancellationTokenSource _srcCancel = new CancellationTokenSource(); 
      m_cancellationTokenSources.Add(_testId, _srcCancel); 
      m_tasks.Add(Task.Factory.StartNew(_testId => testRunner<Int32>((Int32)_testId), _testId, _srcCancel.Token)); 
      _testId++; 

      // Attach task 
      #endregion 
     } 
     #endregion 
     else 
     { 
      CancellationTokenSource _srcCancel = new CancellationTokenSource(); 
      m_cancellationTokenSources.Add(_testId, _srcCancel); 
      m_tasks.Add(Task.Factory.StartNew(_testId => testRunner<Int32>((Int32)_testId), _testId, _srcCancel.Token)); 
      _testId++; 
     } 


    } 

    internal static void WaitAll() 
    { 
     Task.WaitAll(m_tasks.ToArray()); 
    } 

    public static Int32 testRunner<T>(T _id) 
    { 
     for (Int32 i = 0; i <= 1000000; i++) 
     { 
      File.AppendAllText(@"C:\TestTemp\" + _id, i.ToString()); 
     } 
     return 2; 
    } 
} 

答えて

1

、そこTask.WhenAny that takes an IEnumerable<Task>があり、one that takes IEnumerable<Task<T>>

var winner = Task.WhenAny(theDictionary.Values); 
+0

私は終わった仕事を取り戻すつもりだが、私は辞書の権利の鍵として使われているIDを失うだろう? :/ –

+1

@GrégoryLはい;だからあなたはそれを再発見するか、タスク上で 'AsyncState'を利用する必要があります –

+0

私はasyncStateについてgoogledしました。私の理解が良ければ、私はタスクにパラメータとして渡したIDを返すことができます?そして、この場合、私はちょうど私がIDを戻すことができるので、私は本当に辞書をもう必要としません。 –

1

Task.WhenAnyの戻り値は次のとおりです。

表しタスク提供されたタスクの1つの完了。 リターンタスクの結果は完了したタスクです。

docsより。

だから、基本的に、あなたがそれに辞書値を渡すことができ、それはいくつかのLINQを使用してIDが、このタスクにアタッチするのは簡単です、ここからそれを待っていることにより、あなたは、終了したタスクを取得します:使用

var task = await Task.WhenAny(_tasks.Values); 
var id = _tasks.Single(pair => pair.Value == task).Key; 
+0

すみません。あなたの答えは非常に簡単かつ簡単な方法で問題に完全に答えているようだが、問題解決の方法だけでなく、私の受胎ミスを指摘してくれたので、Macの答えに行く。とにかくありがとう ! –

関連する問題