2013-07-18 38 views
6

Tôi đã đọc http://msdn.microsoft.com/en-US/library/vstudio/hh191443.aspx. Ví dụ mã:C# async chạy đơn luồng?

async Task<int> AccessTheWebAsync() 
{ 
    // You need to add a reference to System.Net.Http to declare client. 
    HttpClient client = new HttpClient(); 

    // GetStringAsync returns a Task<string>. That means that when you await the 
    // task you'll get a string (urlContents). 
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); 

    // You can do work here that doesn't rely on the string from GetStringAsync. 
    DoIndependentWork(); 

    // The await operator suspends AccessTheWebAsync. 
    // - AccessTheWebAsync can't continue until getStringTask is complete. 
    // - Meanwhile, control returns to the caller of AccessTheWebAsync. 
    // - Control resumes here when getStringTask is complete. 
    // - The await operator then retrieves the string result from getStringTask. 
    string urlContents = await getStringTask; 

    // The return statement specifies an integer result. 
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
    return urlContents.Length; 
} 

Trang cũng nói:

Các async và chờ đợi từ khóa không gây đề bổ sung để được tạo ra. Các phương thức không đồng bộ không yêu cầu đa luồng vì một phương thức async không chạy trên chủ đề riêng của nó

Điều này "không tạo chuỗi bổ sung" được áp dụng trong phạm vi của phương thức được đánh dấu là không đồng bộ?

Tôi sẽ tưởng tượng để cả GetStringAsync và AccessTheWebAsync chạy cùng một lúc (nếu không GetStringAsync sẽ không bao giờ kết thúc như AccessTheWebAsync kiểm soát ngay bây giờ), cuối cùng GetStringAsync phải chạy trên một luồng khác từ chuỗi của AccessTheWebAsync.

Đối với tôi, viết phương pháp async chỉ hữu ích tại không bổ sung thêm chủ đề khi các phương pháp đó đang chờ đợi cũng là async (mà đã sử dụng thêm chủ đề để làm việc của riêng mình song song)

là hiểu biết của tôi có đúng không?

Trả lời

12

Đây là chìa khóa cho sức mạnh của async. GetStringAsync và các hoạt động không đồng bộ tự nhiên khác không yêu cầu chuỗi. GetStringAsync chỉ gửi yêu cầu HTTP và đăng ký cuộc gọi lại để chạy khi máy chủ trả lời. Không cần một chủ đề chỉ để chờ máy chủ trả lời.

Trong thực tế, nhóm chỉ được sử dụng một chút xíu. Trong ví dụ trên, cuộc gọi lại được đăng ký bởi GetStringAsync sẽ thực thi trên chuỗi chủ đề của chuỗi, nhưng tất cả những gì nó làm là thông báo AccessTheWebAsync rằng nó có thể tiếp tục thực hiện.

Tôi có một số async intro blog post bạn có thể thấy hữu ích.

+0

Bạn có thể giải thích ý bạn là gì bởi "hoạt động không đồng bộ tự nhiên không yêu cầu chuỗi"? Công việc đó có thể được xử lý như thế nào? Bạn đang nói về một thời gian của một thread được phân chia giữa các nhiệm vụ? –

+1

@VincePanuccio: Đó là một chút dài để mô tả trong một bình luận, nhưng tôi có [một bài đăng blog] (http://blog.stephencleary.com/2013/11/there-is-no-thread.html) mà đi vào chi tiết. –

1

tôi sẽ tưởng tượng theo thứ tự cho cả GetStringAsync và AccessTheWebAsync để được chạy cùng lúc ...

Họ không chạy cùng một lúc (ít nhất là không theo cách bạn đang suy nghĩ). Bây giờ, nếu HttpClient.GetStringAsync tự

  • bắt đầu làm việc trên một chủ đề khác nhau, sau đó mã mà có thể chạy cùng một lúc, -HOẶC-
  • Đã có một chờ đợi (với ConfigureAwait (false)), sau đó các Phần còn lại của công việc trong phương pháp đó sẽ được sắp xếp vào các chủ đề chủ đề hồ (và do đó, mã có thể được chạy cùng một lúc.

Vấn đề là rằng tuyên bố một phương pháp như async và/hoặc sử dụng await, không gây ra phương thức mà bạn đang cho phép chạy trên một luồng riêng biệt (bạn sẽ phải làm điều đó itly).

Lưu ý: Nếu không có mã (hoặc tài liệu) của phương pháp không đồng bộ khác, bạn không thực sự biết số tiền đó được chạy đồng bộ.Nó không thực sự bắt đầu là không đồng bộ cho đến khi phương thức đó thực hiện một số await hoặc bắt đầu làm việc trên một luồng khác (thường bằng cách bắt đầu một số mới Task)

-3

Tác giả đang nói ở đây là chỉ cần sử dụng async và chờ từ khóa ở đâu đó không làm cho phương thức hiện tại chạy trên một luồng khác. Hãy điều tra những gì xảy ra trong mã được cung cấp.

async Task<int> AccessTheWebAsync() 
{ 
    // You need to add a reference to System.Net.Http to declare client. 
    HttpClient client = new HttpClient(); 

    // GetStringAsync returns a Task<string>. That means that when you await the 
    // task you'll get a string (urlContents). 
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); 

Mọi thứ đến thời điểm này đã được thực thi trong một chuỗi. Tại thời điểm này, các cuộc gọi client.GetStringAsync có thể spin ra một chủ đề mới (mặc dù điều này không phải là guarenteed cho bất kỳ phương pháp async). Cần lưu ý rằng mặc dù phương thức GetStringAsync về cơ bản khởi động trên luồng hiện tại này (như thực sự thực hiện cuộc gọi), nhưng việc đọc phản hồi sẽ thực hiện trong một luồng khác khi nó đã trả về. Điều này được đại diện bởi nó trả về một đối tượng Task. Tác vụ có thể đại diện cho một bit đã hoàn thành công việc, một chủ đề thứ cấp đang thực thi, hoặc một đơn vị công việc được lập lịch biểu để thực thi sau này.

DoIndependentWork(); 

Điều này bây giờ thực hiện trên chuỗi chính của chúng tôi, sau khi cuộc gọi đã được xếp hàng đợi (hoặc có thể được gửi). Do đó, điều này có thể xảy ra trong khi chờ yêu cầu được trả lại. Lưu ý rằng chúng tôi vẫn đang trong chuỗi chính của chúng tôi.

string urlContents = await getStringTask; 

Tại thời điểm này, chuỗi của chúng tôi trả về. .NET sẽ tạo ra một hàm liên tục có chứa phần còn lại của phương thức (return urlContents.Length;) sẽ tự động được gọi cho chúng ta khi getStringTask hoàn thành trên một chuỗi riêng của nó. Tại thời điểm đó, một chủ đề mới sẽ nhận được sự tiếp tục.

Thông qua tất cả điều này, toàn bộ những gì chúng tôi đã viết bằng phương pháp async của chúng tôi, cho đến từ khóa đang chờ, chạy trong một chuỗi duy nhất. Chắc chắn, chúng tôi gọi một phương pháp khác có thể xảy ra để sinh ra một chuỗi khác, nhưng không có gì chúng tôi đã làm để tạo một chuỗi khác chỉ bằng cách sử dụng các từ khóa không đồng bộ/chờ đợi. Sự tiếp nối ở cuối có thể được gọi bằng một luồng khác, nhưng sau khi hàm ban đầu của chúng ta thực sự trả về (Đó là lý do hàm của chúng ta trả về một đối tượng Task, để biểu diễn công việc có thể chưa hoàn thành khi bất kỳ cuộc gọi nào trả về hàm này) .

+1

Câu trả lời này hoàn toàn sai. Đối tượng 'Task' không nhất thiết là mã; đặc biệt, 'GetStringAsync' sẽ không bao giờ quay lên một luồng khác để đợi máy chủ. –

0

Có một chuỗi được lấy từ nhóm chủ đề cho thao tác nếu cần. Trong trường hợp của một giao diện điều khiển (không thảo luận về chủ đề giao diện người dùng hoặc các chủ đề IO), chuỗi hiện tại nằm trong bảng điều khiển và một luồng khác được thực hiện để thực thi và chuỗi mới này là luồng thực thi phần còn lại của thao tác.