2017-01-22 24 views
5

Hãy xem xét đoạn mã này:Tại sao Task.Factory.StartNew trả về ngay lập tức trong khi Task.Run không?

Task[] tasks = new Task[4]; 
for (var i = 0; i < tasks.Length; ++i) { 
    tasks[i] = Task.Run(async() => 
    { 
     await Task.Delay(4000); 
    }); 
} 
for (var i = 0; i < tasks.Length; ++i) 
    await tasks[i]; 

Console.WriteLine("Done!"); 

Điều này hoạt động như mong đợi, lấy 4,000 mili giây để thực thi. Tuy nhiên, nếu tôi trao đổi Task.Run với Task.Factory.StartNew thì chỉ mất 0,006 ms!

Mọi người có thể giải thích lý do không?

Trả lời

3

Ok, tôi tìm thấy câu trả lời bản thân mình sau khi đọc bài viết này https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/

Bằng việc sử dụng từ khóa async đây, trình biên dịch sẽ lập bản đồ đại biểu này là một Func<Task<int>>: cách gọi các đại biểu sẽ trở lại các Task<int> để đại diện cho việc hoàn thành cuối cùng của cuộc gọi này. Và vì đại biểu là Func<Task<int>>, TResultTask<int> và do đó loại ‘t’ sẽ là Task<Task<int>>, chứ không phải Task<int>.

Vì vậy, mã này hoạt động như mong đợi:

Task[] tasks = new Task[4]; 
for (var i = 0; i < tasks.Length; ++i) { 
    tasks[i] = Task.Factory.StartNew(async() => 
    { 
     await Task.Delay(4000); 
    }); 
} 
for (var i = 0; i < tasks.Length; ++i) 
    await await (tasks[i] as Task<Task>); 

Console.WriteLine("Done!"); 

Mà có thể được thực hiện cũng sử dụng Unwrap:

Task[] tasks = new Task[4]; 
for (var i = 0; i < tasks.Length; ++i) { 
    tasks[i] = Task.Factory.StartNew(async() => 
    { 
     await Task.Delay(4000); 
    }).Unwrap(); 
} 
for (var i = 0; i < tasks.Length; ++i) 
    await tasks[i]; 

Console.WriteLine("Done!"); 
3

Câu trả lời là here

có sự khác biệt trong hành vi giữa hai phương pháp liên quan đến: Task.Run (Action) theo mặc định không cho phép các nhiệm vụ con bắt đầu với tùy chọn TaskCreationOptions.AttachedToParent để đính kèm vào dụ công tác hiện tại, trong khi StartNew (Action) không

Vì vậy, Task.Run sẽ đợi trong khi thực hiện sẽ kết thúc và Task.Factory.StartNew trả lại tác vụ ngay lập tức.

5

Mọi người có thể giải thích lý do không?

Đặt đơn giản, StartNew không hiểu async đại biểu.

Vì vậy, when your delegate returns an incomplete task at its first await, StartNew xem lối ra của đại biểu và xem xét công việc của nó hoàn tất. Đây là lý do tại sao nó trả về một Task<Task> tại đây. Task.Run có logic đặc biệt để xử lý các đại biểu không đồng bộ, tự động mở tác vụ bên trong.

Đây chỉ là một trong những cạm bẫy khi sử dụng StartNew với mã không đồng bộ; Tôi bao gồm chi tiết này và các thông tin chi tiết khác trong bài đăng trên blog của tôi StartNew is Dangerous.

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