Câu hỏi Là Async đang chờ từ khóa tương đương với một lambda ContinueWith?


Ai đó có thể vui lòng nhập đủ thông tin để xác nhận xem tôi có hiểu từ khóa Async đang chờ chính xác không? (Sử dụng phiên bản 3 của CTP)

Vì vậy, đến nay tôi đã làm việc ra rằng chèn từ khóa chờ đợi trước khi một cuộc gọi phương thức cơ bản có 2 điều, A. Nó tạo ra một sự trở lại ngay lập tức và B. Nó tạo ra một "tiếp tục" được gọi khi hoàn thành lời gọi phương thức async. Trong mọi trường hợp, việc tiếp tục là phần còn lại của khối mã cho phương thức.

Vì vậy, những gì tôi tự hỏi, là hai bit mã tương đương về mặt kỹ thuật, và nếu như vậy, điều này về cơ bản có nghĩa là từ khóa chờ đợi là giống hệt nhau để tạo ra một ContinueWith Lambda (Tức là: về cơ bản một trình biên dịch phím tắt cho một)? Nếu không, sự khác biệt là gì?

bool Success =
    await new POP3Connector(
        "mail.server.com", txtUsername.Text, txtPassword.Text).Connect();
// At this point the method will return and following code will
// only be invoked when the operation is complete(?)
MessageBox.Show(Success ? "Logged In" : "Wrong password");

VS

(new POP3Connector(
    "mail.server.com", txtUsername.Text, txtPassword.Text ).Connect())
.ContinueWith((success) =>
    MessageBox.Show(success.Result ? "Logged In" : "Wrong password"));

76
2018-01-07 03:53


gốc




Các câu trả lời:


Ý tưởng chung là chính xác - phần còn lại của phương pháp được thực hiện thành một sự tiếp tục của các loại.

Các bài đăng trên blog "đường dẫn nhanh" có chi tiết về cách async/await chuyển đổi trình biên dịch hoạt động.

Sự khác biệt, ngoài đỉnh đầu của tôi:

Các await từ khóa cũng sử dụng khái niệm "lập lịch biểu ngữ cảnh". Ngữ cảnh lập lịch là SynchronizationContext.Current nếu nó tồn tại, rơi trở lại TaskScheduler.Current. Tiếp tục sau đó chạy trên ngữ cảnh lập lịch biểu. Vì vậy, một xấp xỉ gần hơn sẽ là để vượt qua TaskScheduler.FromCurrentSynchronizationContext vào ContinueWith, rơi trở lại TaskScheduler.Current Nếu cần.

Thực tế async/await thực hiện dựa trên kết hợp mẫu; nó sử dụng một mẫu "awaitable" cho phép những thứ khác ngoài các nhiệm vụ được chờ đợi. Một số ví dụ là các API không đồng bộ của WinRT, một số phương pháp đặc biệt như Yield, Các quan sát Rx và ổ cắm đặc biệt chờ đợi mà không nhấn GC cứng. Nhiệm vụ rất mạnh mẽ, nhưng chúng không phải là thứ duy nhất chờ đợi.

Một sự khác biệt nhỏ về nitpicky là: nếu sự chờ đợi đã hoàn thành, thì async phương thức không thực sự trở lại vào thời điểm đó; nó tiếp tục đồng bộ. Vì vậy, nó giống như đi qua TaskContinuationOptions.ExecuteSynchronously, nhưng không có sự cố liên quan đến ngăn xếp.


76
2018-01-07 04:39



rất hay nói - Tôi cố gắng trì hoãn các bài viết của Jon vì chúng rộng hơn nhiều so với bất cứ điều gì tôi có thời gian để đưa vào một câu trả lời về SO, nhưng Stephen hoàn toàn đúng. WRT những gì đang chờ đợi (và GetAwaiter nói riêng), bài viết của anh ấy # 3 là rất hữu ích IMHO :) msmvps.com/blogs/jon_skeet/archive/2011/05/13/… - James Manning
Vị trí của Stephen ở đây. Đối với các ví dụ đơn giản, thật dễ dàng để nghĩ rằng async / await chỉ là một phím tắt cho ContinueWith - tuy nhiên, tôi thích nghĩ về nó ngược lại. Async / await thực sự là một biểu hiện mạnh mẽ hơn về những gì bạn sử dụng để sử dụng ContinueWith cho. Vấn đề là ContinueWith (...) sử dụng lambdas, và cho phép thực hiện để được chuyển sang tiếp tục, nhưng các khái niệm luồng điều khiển khác như vòng lặp là không thể nếu bạn phải đặt một nửa của vòng lặp trước ContinueWith (.. .) và nửa kia sau. Bạn kết thúc với chuỗi liên tục thủ công. - Theo Yaung
Một ví dụ khác mà async / await là biểu cảm hơn nhiều so với ContinueWith (...) đang chảy các ngoại lệ. Bạn có thể chờ đợi nhiều lần trong cùng một khối thử và cho mỗi giai đoạn thực hiện, ngoại lệ của chúng có thể được chuyển vào cùng một khối catch (...) mà không cần phải viết tấn mã làm điều đó một cách rõ ràng. - Theo Yaung
Phần cuối cùng của async / await đáng chú ý là nó là một "khái niệm cấp cao hơn" trong khi ContinueWith (...) là hướng dẫn sử dụng và rõ ràng có lambdas, đại biểu sáng tạo, vv Với khái niệm cấp cao hơn có nhiều cơ hội để tối ưu hóa - vì vậy Ví dụ, nhiều người đang chờ đợi trong cùng một phương thức thực sự "chia sẻ" cùng một kết cấu lambda (giống như chi phí của một lambda đơn), trong khi ContinueWith (...) nhận được chi phí mỗi khi bạn gọi nó, bởi vì bạn đã viết một lambda rõ ràng, do đó trình biên dịch cung cấp cho bạn. - Theo Yaung
Bạn có thể giải thích về điều gì sẽ xảy ra nếu điều đó Connect phương pháp đã ném một ngoại lệ trong mã OPS? Sẽ ContinueWith vẫn bị sa thải trong trường hợp đó? Và nếu có, có cách tiếp cận tốt hơn để có được cái đó hành vi chỉ sử dụng async/await? Tôi muốn chạy hai nhiệm vụ sau cái kia, và tôi không quan tâm nếu cái đầu tiên ném một ngoại lệ, cái thứ hai sẽ luôn luôn chạy. AFAICT, nếu tôi đi với sự chờ đợi, tôi sẽ phải xử lý một cách rõ ràng các ngoại lệ và tạo ra ngoại lệ tổng hợp. - julealgon


Đó là "cơ bản" đó, nhưng mã được tạo ra không chỉ đúng hơn. Để biết thêm chi tiết về mã được tạo, tôi rất muốn giới thiệu loạt bài Eduasync của Jon Skeet:

http://codeblog.jonskeet.uk/category/eduasync/

Đặc biệt, bài đăng # 7 được đưa vào nội dung được tạo (như của CTP 2) và tại sao, vì vậy có thể phù hợp với những gì bạn đang tìm kiếm tại thời điểm này:

http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method/

EDIT: Tôi nghĩ rằng nó có thể là chi tiết hơn những gì bạn đang tìm kiếm từ câu hỏi, nhưng nếu bạn đang tự hỏi những gì trông giống như khi bạn có nhiều đang chờ đợi trong phương pháp, đó là bao gồm trong bài # 9 :)

http://codeblog.jonskeet.uk/2011/05/30/eduasync-part-9-generated-code-for-multiple-awaits/


8
2018-01-07 04:38