async + await == đồng bộ hóa?


24

Tình cờ thấy bài đăng này nói về việc thực hiện các yêu cầu web không đồng bộ.

Bây giờ đơn giản sang một bên, nếu trong thế giới thực, tất cả những gì bạn làm là thực hiện một yêu cầu không đồng bộ và chờ đợi nó ở dòng tiếp theo, không giống như thực hiện cuộc gọi đồng bộ ở vị trí đầu tiên phải không?


5
Không chính xác. Mã của bạn là đồng bộ theo nghĩa không có gì xảy ra cho đến khi bạn nhận được kết quả. Tuy nhiên, bên dưới, có lẽ bạn đã từ bỏ luồng mà bạn đang chạy cho đến khi phương thức async trở lại, sau đó được gán một luồng khác để tiếp tục thực thi.
R0MANARMY

2
đó là nhưng với async, bạn có thể thực hiện một async khác cùng một lúc và sau đó chờ đợi 2, với đồng bộ hóa, điều này là không thể
ratchet freak

Đây là một bài viết ( tomasp.net/blog/async-compilation-iternals.aspx ) thảo luận về một số phần mềm không đồng bộ trong C # - đây là một phần của loạt bài viết về lập trình không đồng bộ trong C # và F #.
paul

@ratchetfreak: Vâng, không cần phải nói nếu bạn đang thực hiện nhiều cuộc gọi.
Ông trùm

@ R0MANARMY: Nếu ứng dụng của bạn đang làm những việc khác, thì có và async + await cho phép điều đó. Akim nói nó tốt nhất! Nhưng hãy tưởng tượng mã không nằm trong trình xử lý button_click hoặc bất kỳ trình xử lý sự kiện nào như vậy cho vấn đề đó. Nếu ai đó sao chép mã một cách mù quáng (async + await lines), vào bất kỳ phương thức nào, điều đó có thể dẫn đến ấn tượng sai lệch rằng mã của bạn không đồng bộ nhưng thực tế có thể không.
Ông trùm

Câu trả lời:


32

Không, async + await != synctiếp tục

Từ MSDN 'Lập trình không đồng bộ với Async và Await (C # và Visual Basic)'

Các phương thức Async được dự định là các hoạt động không chặn. Một biểu thức chờ trong phương thức async không chặn luồng hiện tại trong khi tác vụ được chờ đang chạy. Thay vào đó, biểu thức đăng ký phần còn lại của phương thức dưới dạng tiếp tục và trả lại quyền điều khiển cho người gọi phương thức async .

Ví dụ, thực thi async sẽ không chặn luồng UI và Some TextBox.Textsẽ được cập nhật sau khi quá trình tải xuống kết thúc

private async void OnButtonClick()
{
   SomeTextBox.Text = await new WebClient().DownloadStringTaskAsync("http://stackoverflow.com/");
}

Rất độc đáo nói!
Ông trùm

Bạn có thể giải thích chi tiết hơn Có phải bạn đang nói rằng ... nếu không có điều này ... bạn sẽ không thể tương tác với giao diện người dùng ... vì điều này sẽ nằm trên luồng chính. Vì vậy, điều này có nghĩa là điều này chỉ có thể áp dụng trong một chương trình loại ứng dụng được gắn vào web nơi tương tác tách biệt với luồng máy chủ web. Vì vậy, trong một shell nut, điều này chỉ trở nên quan trọng tức là không đồng bộ hóa * khi luồng chính của bạn là luồng đang chạy. Điều này sẽ không tạo ra hành vi bất ngờ, tức là trong Ứng dụng (1 luồng chính), hai nút được nhấp .. nhưng bạn có thể nhấp vào 1 mà không cần hoàn thành lần đầu tiên không?
Seabizkit 7/12/2016

Thế còn Console.WriteLine(await GetStringOverNetwork());? Điều gì nếu bạn cần đầu ra của lời gọi không đồng bộ? Chương trình sẽ chặn truy cập đầu tiên, ngay cả khi luồng có khả năng tiếp tục thực thi?
Andrew

6

Không, nó không giống nhau.

asyncKhối mã của bạn đang chờ awaitcuộc gọi trở lại để tiếp tục, tuy nhiên phần còn lại của ứng dụng của bạn không chờ và vẫn có thể tiếp tục như bình thường.

Ngược lại, một cuộc gọi đồng bộ sẽ khiến toàn bộ ứng dụng hoặc luồng của bạn chờ cho đến khi mã hoàn thành thực thi để tiếp tục với bất kỳ điều gì khác.


không thể thực hiện cuộc gọi đồng bộ hóa dưới dạng async + đang chờ?
ratchet freak

@ratchetfreak Tôi nghĩ rằng có một số chi phí để thiết lập await / async, vì vậy tôi không nghĩ rằng bạn muốn mã hóa toàn bộ ứng dụng của mình với nó. Tôi chỉ sử dụng nó để thực thi các khối mã có khả năng chạy dài để nó không khóa các ứng dụng của tôi. :)
Rachel

5

Vui lòng cho phép tôi làm rõ mọi thứ liên quan đến async / await.

Khi gặp phải sự chờ đợi, máy trạng thái cơ bản cho phép điều khiển được trả về ngay lập tức. Sau đó, khi cuộc gọi chờ được hoàn thành, máy trạng thái bên dưới cho phép thực thi tiếp tục tại đường dây sau cuộc gọi được chờ.

Do đó, khối async không bị chặn cũng như không chờ cuộc gọi chờ đợi kết thúc; Kiểm soát được trả về ngay lập tức khi gặp lệnh chờ.

Bộ máy trạng thái cơ bản là một phần của "ma thuật" đằng sau việc sử dụng async / await không bị bỏ qua và bỏ qua.


2

Tôi đã vấp phải điều này với cùng một câu hỏi trong đầu, nhưng sau khi đọc các câu trả lời, câu hỏi dường như kéo dài, bối rối bởi các tham chiếu đến "ma thuật dưới mui xe".

Từ lập trình không đồng bộ đã đề cập ở trên :

  • Các asynctừ khóa biến một phương pháp thành một phương pháp async, cho phép bạn sử dụng các awaittừ khóa trong cơ thể của nó.
  • Khi awaittừ khóa được áp dụng, nó tạm dừng phương thức gọi và mang lại quyền kiểm soát cho người gọi cho đến khi nhiệm vụ được chờ hoàn thành.
  • awaitchỉ có thể được sử dụng bên trong một asyncphương thức.

Liệu bối cảnh gặp phải awaitcó bị chặn?

  • . Đó thực chất là một rào cản đồng bộ hóa cục bộ để duy trì trạng thái đã biết trong bối cảnh thực thi; ngoại trừ các bối cảnh khác, nếu có, không được tham gia.

Có phải phần còn lại của khối ứng dụng tại await?

  • Nó phụ thuộc vào cách ứng dụng của bạn được viết. Nếu đó là một loạt các awaittác vụ ed phụ thuộc được khởi chạy tuần tự trong cùng một bối cảnh (xem: Cố gắng hiểu một số hành vi không đồng bộ / chờ đợi )

    await asyncCall1();
    await asyncCall2();  // waits for asyncCall1() to complete

    Bằng cách này, mỗi cái awaitsẽ chặn sinh sản của cái tiếp theo.

    Mặt khác, các tác vụ phụ thuộc tương tự được khởi chạy song song sẽ thực thi song song và bối cảnh sẽ chỉ chặn ở mức tương ứng. await:

    Task<int> t1 = asyncCall1();
    Task<string> t2 = asyncCall2();  // runs in parallel with asyncCall1()
    int val = await t1;
    string str = await t2;  // waits for asyncCall1() to complete

    Nói chung, việc awaitthực hiện mang lại cho bối cảnh bên ngoài, từ đó bối cảnh hiện tại được gọi. Tuy nhiên, nếu bối cảnh bên ngoài đang chờ đợi hiện tại, thì nó giống như một chuỗi liên tiếp awaittrong cùng bối cảnh.

Vì vậy, để gặt hái những asynclợi ích, người ta cần thiết kế ứng dụng để chạy một số bối cảnh song song (UI, data-client, v.v.), sau đó awaittrong một bối cảnh mang lại sự thực thi cho các bối cảnh khác, vì vậy toàn bộ ứng dụng sẽ không chặn trên một cá nhân await.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.