2017-12-18 235 views
1

我目前正在編寫一個服務,它將爲他在數據庫中找到的每個「等待進程」請求創建Task。使用Task.WhenAny與字典

該過程可能很長,並且我希望服務在每次必須取消任務時檢查它,如果是這種情況我想用令牌取消任務。所以我需要存儲鏈接到任務的請求的ID。

我在想,我有我的字典靜態類如下:

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

,我不知道這是否是更好的解決方案存在,但它仍然是一個工作,我認爲。

現在我想做一個Task.WhenAny(..)來知道其中一個是否結束。問題是Task.WhenAny(..)接受一個數組,但不是一個Dictionary。我沒有看到任何關於將字典傳遞給WhenAny的任何事情,並且在開始處理很長的整個過程之前,我希望爲我的工作流程的每個關鍵點提供解決方案。我可以獲得字典值的列表,但我可能會丟失id鏈接。所以我不知道該怎麼辦?

有沒有解決方案?我不想重新創建自己的「自己的」WhenAny,我甚至不知道是否有可能,但我認爲我只能解析每一行的狀態。但如果這是唯一的選擇,我會的。

我也打開這樣一個事實,即以這種方式存儲請求的ID不是一個好辦法,在這種情況下,我可以接受任何其他建議。


編輯:CODE ACORDING進行答辯 我使用此代碼,這似乎是工作結束。現在我將測試更復雜的任務,而不僅僅是一個文件寫入! :)

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égoryLyes;所以你要麼需要重新找到它,要麼使用任務上的'AsyncState' –

+0

我剛剛搜索了一下asyncState,所以如果我的理解很好,我可以找回我作爲參數傳遞給任務的ID ?在這種情況下,我不再需要字典了,因爲我可以將ID退回。 –

1

Task.WhenAny返回值是:代表

任務完成提供的任務之一。 返回任務的結果是已完成的任務。

docs

所以基本上你可以傳遞給它的字典值和等待它,你會得到,這是完成了任務,從這裏很容易附着在該任務是使用一些LINQ ID:

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

處尋找任務,我很抱歉。你的回答似乎以非常簡短的方式完美地回答了這個問題,但是我會回答Mac的答案,因爲他給了我不僅解釋如何解決問題的解釋,而且指出了我的概念錯誤。不管怎麼說,還是要謝謝你 ! –