2013-04-11 17 views
12

Widziałem wiele innych pytań podobnych do tego, ale nie znalazłem tam odpowiedzi.Jak zmusić Task.Factory.StartNew do wątku tła?

Moim problemem było to, że było stworzenie wątki z następującym przepływu:

private void btn_Click(object sender, EventArgs e) 
{ 
    service.GetCount(
     (count, ex) => 
     { 
      if (ex != null) 
       return; 

      for (int i = 0; i < count; i++) 
      { 
       service.Get(onItemReceived, i); 
      } 
     } 
    ); 
} 

public void GetCount(Action<int, Exception> callback) 
{ 
    var callingThread = TaskScheduler.FromCurrentSynchronizationContext(); 

    Func<int> action =() => 
    { 
     return client.GetCount(); // Synchronous method, could take a long time 
    }; 

    Action<Task<int>> completeAction = (task) => 
    { 
     Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception; 

     if (callback != null) 
      callback(task.Result, ex); 
    }; 

    Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread); 
} 

public void Get(Action<object, Exception> callback, int index) 
{ 
    var callingThread = TaskScheduler.FromCurrentSynchronizationContext(); 

    Func<object> action =() => 
    { 
     return client.Get(index); // Synchronous method, could take a long time 
    }; 

    Action<Task<object>> completeAction = (task) => 
    { 
     Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception; 

     if (callback != null) 
      callback(task.Result, ex); 
    }; 

    Task.Factory.StartNew(action).ContinueWith(completeAction, callingThread); 
} 

W ten sposób, każda z metod asynchronicznych moją usługę byłby callback nić były pierwotnie zwany na (zwykle wątku UI). Tak więc symuluję działanie słów kluczowych oczekujących/asynchronicznych (nie mogę używać programu .NET 4.5).

Problem z tym wzorcem polega na tym, że po pierwszym wywołaniu komunikatu "ContinueWith" otrzymuję niewytłumaczalną blokadę do wątku interfejsu użytkownika. Tak więc w tym przypadku, jeśli spróbuję odrodzić 5 wątków dla każdego procesu funkcji synchronicznej, będą one wykonywać 1 zamiast 1 zamiast równolegle i będą blokować wątek UI podczas tego procesu, nawet jeśli spróbuję określić TaskCreationOptions.LongRunning .

To się nigdy nie zdarza z moim pierwszym wywołaniem Task.Factory.StartNew, to zdarza się tylko w następnych połączeniach od wewnątrz pierwszego wywołania zwrotnego.

+0

Możliwe duplikaty [Jak zagwarantować nowy wątek jest tworzony przy użyciu metody Task.StartNew] (https://stackoverflow.com/questions/8039936/how-to-guarantee-a-new-thread-is- create-when-using-the-task-startnew-method) –

Odpowiedz

23

Aby wymusić rozpoczęcie nowego wątku, należy określić TaskScheduler.Default w wywołaniu Task.Factory.StartNew następująco:

Task.Factory.StartNew(action, 
         CancellationToken.None, 
         TaskCreationOptions.None, 
         TaskScheduler.Default).ContinueWith(completeAction); 

W moich testów nie trzeba określić TaskCreationOptions .LongRunning w celu wymuszenia wątku tła, choć nie powinno to boleć.

+0

'LongRunning' wymusza stworzenie zupełnie nowego wątku * nici wątku *. – Servy

+2

@Servy - to nic nie wymusza, jest to podpowiedź dla harmonogramu. –

+0

@HenkHolterman Teoretycznie tak, to prawda. W praktyce, w obecnej implementacji powoduje tworzenie nowego wątku. Zgadzam się, może najlepiej byłoby założyć, że jest możliwe, że nie, należy założyć, że oznaczanie zadania tak długo działającego, że tak naprawdę nie będzie zużywać dodatkowych zasobów. – Servy

Powiązane problemy