2017-12-18 20 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 주문에 따라 제품에 내가 일하게 될 것 같다이 코드를 사용하여 종료 답변. 이제는 파일 작성이 아니라보다 복잡한 작업으로 테스트 해 보겠습니다! :)

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

나는 끝난 일들을 되 찾을 것이지만, 나는 사전에있는 열쇠로 사용 된 이드를 풀어 놓을 것인가? :/ –

+1

@ GrégoryL 예; 그래서 다시 찾거나, 작업에서 AsyncState를 사용할 필요가 있습니다. –

+0

asyncState에 대해 봤습니다. 이해가 잘 된 경우 작업에 매개 변수로 전달한 ID를 다시 얻을 수 있습니다. ? 그리고이 경우 나는 ID를 다시 얻을 수 있기 때문에 더 이상 사전을 필요로하지 않습니다. –

1

Task.WhenAny 반환 값은 다음과 같습니다

작업은 나타냅니다 제공된 작업 중 하나가 완료되었습니다. 리턴 태스크의 결과는 완료된 태스크입니다.

docs.

그래서 기본적으로 당신이 그것에 사전 값을 전달할 수 있으며, 어떤 LINQ를 사용하여 아이디의이 작업에 첨부 할 쉽게 여기에서 기다리고하여이 끝났을 작업을 얻을 것이다 : 사용

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

미안 해요. 당신의 대답은 매우 간단하고 쉬운 방법으로 문제를 완벽하게 대답하는 것처럼 보입니다.하지만 Mac의 대답은 그가 문제를 해결하는 방법뿐만 아니라 내 개념 실수를 지적하면서 설명해주었습니다. 어쨌든 고마워! –