2013-07-15 23 views
6

Tôi đã đọc số article của Eric lippert về async và về những nhầm lẫn mà mọi người có với từ khóa async. ông nói:không đồng bộ - hãy ở lại luồng hiện tại?

nó (async) có nghĩa là “phương pháp này chứa dòng điều khiển mà liên quan đến việc chờ hoạt động không đồng bộ và do đó sẽ được viết lại bởi trình biên dịch vào tiếp tục đi qua phong cách để đảm bảo rằng hoạt động không đồng bộ có thể tiếp tục phương pháp này ở đúng chỗ.”toàn bộ vấn đề của phương pháp async nó mà bạn ở lại trên thread hiện hành càng nhiều càng tốt

tôi không hiểu điều này. Nếu tôi thực hiện một phương thức không đồng bộ (Task) và nó chạy, nó chắc chắn chạy trên một chuỗi khác.

Hơn nữa, Nếu tôi viết một phương pháp sử dụng await, (IMHO) nó giải phóng các dòng điều khiển bình thường, và đang refactored như nhau "ContinueWith" sau đó, vào khác chủ đề.

Tôi đã thử nghiệm nó với (console):

/*1*/ public void StartChain() 
/*2*/ { 
/*3*/   var a = FuncA(); 
/*4*/   Console.WriteLine(a.Result); 
/*5*/ } 
/*6*/ 
/*7*/ public async Task <int> FuncA() 
/*8*/ { 
/*9*/   Console.WriteLine("A--" + Thread.CurrentThread.ManagedThreadId); 
/*10*/   var t = await FuncB(); 
/*11*/   Console.WriteLine("B--" + Thread.CurrentThread.ManagedThreadId); 
/*12*/   return t; 
/*13*/ } 
/*14*/ 
/*15*/ public async Task <int> FuncB() 
/*16*/ { 
/*17*/   Console.WriteLine("C--" + Thread.CurrentThread.ManagedThreadId); 
/*18*/   await Task.Delay(2000); 
/*19*/   Console.WriteLine("D--" + Thread.CurrentThread.ManagedThreadId); 
/*20*/   return 999; 
/*21*/ } 
/*22*/ 
/*23*/ void Main() 
/*24*/ { 
/*25*/   StartChain(); 
/*26*/ } 
/*27*/ 

kết quả là:

A--7 
C--7 
D--17   <-----D and B are on different thread 
B--17 
999 

Vậy điều gì đã Eric nghĩa bằng cách nói "ở trên thread hiện tại"?

chỉnh sửa 1:

trong asp.net nó cũng trở differnt thread ID.

public async Task<int> FuncA() 
{ 
    Response.Write("<br/>C----" + Thread.CurrentThread.ManagedThreadId); 
    var t = await FuncB(); 
    Response.Write("<br/>D----" + Thread.CurrentThread.ManagedThreadId); 
    return t; 
} 

public async Task<int> FuncB() 
{ 
    Response.Write("<br/>E----" + Thread.CurrentThread.ManagedThreadId); 
    await Task.Delay(2000); 
    Response.Write("<br/>F----" + Thread.CurrentThread.ManagedThreadId); 
    return 999; 
} 



protected async void Page_Load(object sender, EventArgs e) 
{ 
    Response.Write("<br/>A----" + Thread.CurrentThread.ManagedThreadId); 
    var a=await FuncA(); 
    Response.Write("<br/>B----" + Thread.CurrentThread.ManagedThreadId); 

} 

A----8 
C----8 
E----8 
F----9 
D----9 
B----9 

chỉnh sửa 2

(sau khi nhận được một câu trả lời)

có vẻ như chủ đề đó được phục vụ chỉ ở các ứng dụng GUI:. Tôi chạy mã này ở Winform

public async Task<int> FuncA() 
     { 
      textBox1.Text +=Environment.NewLine+ "\nC----" + Thread.CurrentThread.ManagedThreadId; 
      var t = await FuncB(); 
      textBox1.Text += Environment.NewLine + "\nD----" + Thread.CurrentThread.ManagedThreadId; 
      return t; 
     } 

     public async Task<int> FuncB() 
     { 
      textBox1.Text += Environment.NewLine + "\nE----" + Thread.CurrentThread.ManagedThreadId; 
      await Task.Delay(2000); 
      textBox1.Text += Environment.NewLine + "\nF----" + Thread.CurrentThread.ManagedThreadId; 
      return 999; 
     } 




     private async void Form1_Load(object sender, EventArgs e) 
     { 
      textBox1.Text += Environment.NewLine + "\nA----" + Thread.CurrentThread.ManagedThreadId; 
      var a = await FuncA(); 
      textBox1.Text += Environment.NewLine + "\nB----" + Thread.CurrentThread.ManagedThreadId; 
     } 

enter image description here

+0

Liên kết tới bài viết bạn đang nhầm lẫn về –

+0

@downvoter - nhận xét sẽ hữu ích. –

+1

Tác vụ bạn đang chờ chạy trên một chuỗi khác. Tất cả các mã khác trong phương thức async chạy trên luồng ban đầu. Chờ đợi không bắt đầu một nhiệm vụ mới. Nó tương đương với một ContinueWith trong chuỗi ORIGINAL. Có nhiều blog thảo luận về điều này. –

Trả lời

9

Hỗ trợ async/await được thêm vào để giúp các lập trình viên viết GUI không bị đóng băng.Đặc biệt hữu ích trong các ứng dụng Store, và lý do cốt lõi nó được thêm vào C# v5, WinRT là một api khá không thân thiện có nhiều phương thức không đồng bộ.

Trường hợp "ở trên cùng một chuỗi" là rất quan trọng trong ứng dụng GUI, bắt buộc vì GUI không an toàn cho luồng. Tuy nhiên nó đòi hỏi một vòng lặp thông điệp, cách duy nhất để lấy mã không đồng bộ để tiếp tục trên cùng một luồng. Vòng lặp tin nhắn là giải pháp cốt lõi cho số producer-consumer problem. Rõ ràng chương trình của bạn không có chương trình, trông rất giống ứng dụng chế độ bảng điều khiển. Do đó bạn không nhận được hành vi này, nó tiếp tục trên một chuỗi công nhân.

Không có vấn đề gì nhiều, bạn thực sự không cần để tiếp tục trên cùng một chuỗi vì bảng điều khiển vẫn an toàn. Vâng, chủ yếu là, không kể khóa đã được thêm vào trong .NET 4.5 khi bạn yêu cầu đầu vào. Điều này tất nhiên cũng có nghĩa là bạn không có một heckofalot sử dụng cho async/await hoặc là, một tác phẩm hoạt động tốt là tốt.

+0

Hơi OT, nhưng tôi vấp phải hành vi bạo lực-đầu vào-đồng bộ kỳ lạ này một chút trước đây. Bạn có biết tại sao họ làm điều này? –

+1

Không có ý kiến. Có một kế hoạch lớn hơn đằng sau nó, cùng một khóa cũng được thêm vào CRT. Có một * nhiều * lập trình viên đang bế tắc trong các chương trình thử nghiệm "Nhấn phím bất kỳ để tiếp tục" của họ, thêm khóa này là một sai lầm. –

+1

Và đã được sửa bằng cách xóa nó. –

10

ngữ Eric Lippert của "chủ đề" được đơn giản hóa. Tôi có một số async/await intro trên blog của mình giải thích cách await sẽ nắm bắt ngữ cảnh hiện tại và sử dụng để tiếp tục phương thức async.

Nếu bạn đang ở trong ngữ cảnh giao diện người dùng, ngữ cảnh là chuỗi giao diện người dùng duy nhất và phương pháp async sẽ tiếp tục trên chuỗi đó. Nếu không, các quy tắc phức tạp hơn một chút. Đặc biệt, các ứng dụng Console không cung cấp bất kỳ ngữ cảnh nào, vì vậy các phương thức async theo mặc định tiếp tục trên nhóm chủ đề.

+0

ive đọc bài viết của bạn nhiều lần. (xem các câu hỏi không đồng bộ cuối cùng của tôi;) –

+0

Tuy nhiên, bài viết trả lời câu hỏi. :) Đọc phần về "SynchronizationContext' và' TaskScheduler' một lần nữa. –

+0

Vì vậy, nó không phải là Chủ đề được lưu giữ. (câu hỏi thực sự của tôi - cảm ơn vì đã trả lời) - nhưng ngữ cảnh (đã được tôi biết đến).? ...? vui lòng xác nhận –

19

Nếu tôi thực thi phương pháp không đồng bộ và chạy, nó chắc chắn chạy trên một chuỗi khác.

Không, nó thường là chạy trên một chuỗi khác. Nó không chắc chắn chạy trên một chuỗi khác.

Ngừng suy nghĩ về chủ đề trong giây lát và suy nghĩ về bản chất của sự không đồng bộ. Bản chất của sự không đồng bộ là:

  • Tôi có một số quy trình làm việc hiện đang thực thi.
  • tôi không thể tiến hành trong công việc này cho đến khi tôi nhận được thông tin X.
  • tôi sẽ làm điều gì đó khác cho đến khi tôi nhận được thông tin X.
  • Tại một số điểm trong tương lai, một khi tôi có X, tôi sẽ trở lại nơi tôi rời khỏi công việc của mình và tiếp tục.

Giả sử bạn đang thực hiện thuế và ở giữa luồng công việc phức tạp này, bạn có bổ sung lớn để thực hiện. Bạn có thể thực hiện một vài thao tác sau đó nhớ bạn đang ở đâu và đi ăn trưa. Sau đó quay lại và thực hiện thêm một vài thao tác, sau đó nhớ bạn đang ở đâu và nạp mèo. Sau đó quay lại và thực hiện thêm một vài thao tác, sau đó nhớ bạn đang ở đâu và rửa bát đĩa. Sau đó kết thúc các tính toán và tiếp tục từ nơi bạn đã dừng lại trong luồng công việc của mình.

Đó là phép tính không đồng bộ nhưng chỉ cần một công nhân làm việc đó. Có nhiều công nhân chỉ là một cách đặc biệt thuận tiện để làm không đồng bộ, nó không phải là một yêu cầu.

+0

Eric, nhưng nếu tôi rời khỏi tính toán của tôi và đi nuôi mèo - hoạt động tính toán (mà tôi làm với bút chì và giấy) bị chặn - tôi quay lại .... vì vậy nó có vẻ như hoạt động đồng bộ. hãy sửa tôi. –

+4

Đó không phải là thao tác không đồng bộ. Thực hiện phép tính dài là hoạt động không đồng bộ vì bạn không bị chặn thực hiện công việc khác trong quá trình thực hiện. –

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