2013-04-11 22 views
12

Tôi đã thấy nhiều câu hỏi khác tương tự như vậy nhưng không tìm thấy câu trả lời của tôi ở đó.Làm cách nào để buộc Task.Factory.StartMới một chuỗi nền?

Vấn đề của tôi là tôi đã tạo ra bài với dòng chảy sau:

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); 
} 

Bằng cách này, mỗi người trong số các phương pháp không đồng bộ dịch vụ của tôi sẽ gọi lại thread họ ban đầu được gọi vào (thường thread UI). Vì vậy, tôi mô phỏng cách các từ khóa await/async hoạt động (tôi không thể sử dụng .NET 4.5).

Sự cố với mẫu này là tôi bị khóa không thể giải thích được đối với chuỗi giao diện người dùng sau cuộc gọi đầu tiên tới "ContinueWith". Vì vậy, trong trường hợp này nếu tôi cố gắng sinh ra 5 luồng cho mỗi quá trình, một hàm đồng bộ Nhận, chúng sẽ thực thi 1 bởi 1 thay vì song song và chúng sẽ chặn luồng UI trong khi làm như vậy, ngay cả khi tôi thử chỉ định TaskCreationOptions.LongRunning .

Điều này không bao giờ xảy ra với lần gọi đầu tiên của tôi tới Task.Factory.StartMới, nó chỉ xảy ra với các cuộc gọi tiếp theo từ trong lần gọi lại đầu tiên.

+0

Có thể trùng lặp [Cách đảm bảo chuỗi mới được tạo khi sử dụng phương pháp Task.StartNew] (https://stackoverflow.com/questions/8039936/how-to-guarantee-a-new-thread-is- create-when-using-the-task-startnew-method) –

Trả lời

23

Để buộc sự ra mắt của một chủ đề mới, bạn nên xác định TaskScheduler.Default trong cuộc gọi đến Task.Factory.StartNew như sau:

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

Trong thử nghiệm của tôi bạn không cần phải xác định TaskCreationOptions .LongRunning để buộc một chủ đề nền, mặc dù nó không nên làm tổn thương.

+0

'LongRunning' bắt buộc tạo ra một chuỗi hồ bơi không hoàn toàn mới *. – Servy

+2

@Servy - nó không ép buộc bất cứ điều gì, đó là một _hint_ cho trình lên lịch. –

+0

@HenkHolterman Về lý thuyết, có, đó là chính xác. Trong thực tế, trong việc thực hiện hiện tại, nó dẫn đến một luồng mới được tạo ra. Trong khi tôi đồng ý, có thể tốt nhất là giả sử có thể là không, bạn nên giả định rằng việc đánh dấu một nhiệm vụ là chạy lâu khi nó thực sự không tiêu thụ thêm tài nguyên. – Servy

Các vấn đề liên quan