Không đồng bộ so với đa luồng - Có sự khác biệt không?


133

Có một cuộc gọi không đồng bộ luôn tạo ra một chủ đề mới? Sự khác biệt giữa hai là gì?

Có một cuộc gọi không đồng bộ luôn tạo hoặc sử dụng một chủ đề mới?

Wikipedia nói :

Trong lập trình máy tính, các sự kiện không đồng bộ là những sự kiện xảy ra độc lập với luồng chương trình chính. Các hành động không đồng bộ là các hành động được thực hiện trong sơ đồ không chặn, cho phép luồng chương trình chính tiếp tục xử lý.

Tôi biết các cuộc gọi async có thể được thực hiện trên các chủ đề đơn? Sao có thể như thế được?



1
JavaScript không có các luồng, nhưng nó có các lệnh gọi phương thức không đồng bộ.
Ajedi32

1
Bất kỳ hệ thống nào có một quy trình quản lý nhiều quy trình phụ, quy trình kiểm soát có thể cung cấp hoạt động không đồng bộ của các quy trình phụ. Trong trường hợp JavaScript, trình duyệt cung cấp luồng tính toán. Khi một số chức năng thực hiện cuộc gọi không đồng bộ, trình duyệt có thể lưu trữ ngữ cảnh cho chức năng đó. Bây giờ cùng một chủ đề trình duyệt có thể thay đổi ngữ cảnh để tiếp tục thực hiện chức năng khác. Trong khi đó trong các chương trình đa luồng truyền thống, một luồng thực hiện một khối chức năng để cho phép một luồng khác chạy một chức năng khác. Mỗi luồng thực hiện chức năng riêng của nó một cách đồng bộ.
Mike

Câu trả lời:


82

Câu hỏi này gần như quá chung chung để trả lời.

Trong trường hợp chung, một cuộc gọi không đồng bộ không nhất thiết phải tạo ra một luồng mới. Đó là một cách để thực hiện nó, với nhóm luồng có sẵn hoặc quy trình bên ngoài là những cách khác. Nó phụ thuộc rất nhiều vào ngôn ngữ, mô hình đối tượng (nếu có) và môi trường thời gian chạy.

Không đồng bộ chỉ có nghĩa là luồng cuộc gọi không ngồi và chờ phản hồi, cũng như hoạt động không đồng bộ xảy ra trong luồng gọi.

Ngoài ra, bạn sẽ cần phải cụ thể hơn.


7
Vì vậy, về cơ bản tôi có thể nói: Đa luồng == Sử dụng nhiều luồng để cung cấp lợi ích xử lý cho các tác vụ chuyên sâu của bộ xử lý có thể được hưởng lợi từ nhiều bộ xử lý, cũng như lợi ích trong các tình huống không đồng bộ. Không đồng bộ == một quy trình thực hiện công việc đó, trong khi trạng thái được gọi là quy trình đó không phải đợi quá trình hoàn tất. (Có thể không nhất thiết phải sử dụng nhiều luồng để thực hiện việc này-- tức là các thành phần phần cứng khác có thể chịu trách nhiệm).
Evan Sevy

6
@Michael - Bạn có thể giải thích cách lập trình không đồng bộ có thể xảy ra trong một luồng với một ví dụ không?
Kumar Vaibhav

7
@KumarVaibhav - ví dụ phổ biến nhất là khi một luồng duy nhất hoạt động trên các mục từ hàng đợi (ví dụ: hàng đợi tin nhắn Windows). Nếu chương trình có thói quen gửi các mục vào hàng đợi của riêng nó (một mẫu chung) thì bit mã gửi vật phẩm đó không đợi hoạt động kết thúc mà chỉ trả về. Các hoạt động sẽ được chăm sóc trong khóa học do vòng lặp chính.
Michael Kohne

3
Có thể có một sự khác biệt giữa cách viết mã và cách thực thi. Ví dụ: trong C #, tôi có thể có một phương thức bắt đầu một tác vụ không đồng bộ, phương thức của tôi hoàn toàn không đồng bộ và có thể thực hiện các việc khác mà không cần chờ tác vụ hoàn tất. Tuy nhiên, CLR cũng có thể quyết định thực hiện nhiệm vụ của tôi và thực hiện nó một cách đồng bộ.
Mike

chủ đề nào thực hiện nhiệm vụ chờ đợi? phương thức được đánh dấu bằng đồng bộ hóa được thực thi đồng bộ cho đến khi đạt được từ khóa đang chờ, tại thời điểm này, luồng nào thực hiện tác vụ có thể chờ này?

102

Bất cứ khi nào hoạt động cần xảy ra không đồng bộ không yêu cầu CPU thực hiện công việc, hoạt động đó có thể được thực hiện mà không sinh ra một luồng khác. Ví dụ: nếu hoạt động không đồng bộ là I / O, CPU không phải đợi I / O hoàn thành. Nó chỉ cần bắt đầu hoạt động, và sau đó có thể chuyển sang công việc khác trong khi phần cứng I / O (bộ điều khiển đĩa, giao diện mạng, v.v.) thực hiện I / O hoạt động. Phần cứng cho CPU biết khi nào nó kết thúc bằng cách ngắt CPU và HĐH sẽ cung cấp sự kiện cho ứng dụng của bạn.

Các bản tóm tắt và API cấp cao hơn thường không phơi bày API không đồng bộ cơ bản có sẵn từ HĐH và phần cứng bên dưới. Trong những trường hợp đó, việc tạo ra các luồng để thực hiện các hoạt động không đồng bộ thường dễ dàng hơn, ngay cả khi luồng được sinh ra chỉ chờ hoạt động I / O.

Nếu hoạt động không đồng bộ yêu cầu CPU thực hiện công việc, thì nhìn chung hoạt động đó phải diễn ra trong một luồng khác để nó thực sự không đồng bộ. Thậm chí sau đó, nó thực sự sẽ chỉ không đồng bộ nếu có nhiều hơn một đơn vị thực thi.


1
Giải thích rõ, Cảm ơn bạn; nhưng tôi có một câu hỏi ở đây Bạn đã đề cập rằng "Ví dụ: nếu hoạt động không đồng bộ là I / O, CPU không phải đợi I / O hoàn tất. Nó chỉ cần bắt đầu hoạt động". Câu hỏi của tôi là khi chương trình được phân luồng đơn và nói trong dòng mã 3, bạn gọi một thao tác I / O, sau đó làm thế nào bạn có thể bắt đầu hoạt động trong dòng 3 và thực hiện dòng 4 mà không cần chờ hoạt động I / O hoàn thành ? Đối với tôi, tôi phải đặt mã ở dòng 3 trong một luồng mới để đạt được dòng 4 để thực thi mà không cần chờ hoàn thành thao tác I / O. [Phối cảnh Java pgm]
nhện

1
Lý do là, mặc dù CPU không phải chờ, CPU sẽ đợi hoạt động I / O hoàn tất ... Tôi tin rằng đoạn thứ hai của bạn là câu trả lời cho truy vấn của tôi. Trong trường hợp như vậy, tôi cần kết luận rằng trong Java, các cuộc gọi không đồng bộ cần được thực hiện trong một luồng khác. Vui lòng sửa cho tôi nếu tôi sai hoặc cho tôi biết nếu tôi phải đăng một SO qn mới
nhện

@sperman Một số ngôn ngữ, như Node.js, có mô hình lập trình không đồng bộ. Ngôn ngữ và thời gian chạy cung cấp các phần dựng sẵn cho phép dòng 4 được thực thi trong cùng một luồng, ngay cả trước khi hoạt động IO hoàn thành. Điều này đạt được bởi dòng 3 cung cấp một cuộc gọi lại mà bộ thực thi sẽ gọi khi IO kết thúc.
jrahhali

@sperman có thể ... chức năng Async của hệ điều hành chỉ trả về sai hoặc một cái gì đó trực tiếp.
Byeongin Yoon

18

Không, các cuộc gọi không đồng bộ không phải lúc nào cũng liên quan đến các chủ đề.

Họ thường bắt đầu một số loại hoạt động tiếp tục song song với người gọi. Nhưng hoạt động đó có thể được xử lý bởi một quy trình khác, bởi HĐH, bởi phần cứng khác (như bộ điều khiển đĩa), bởi một số máy tính khác trên mạng hoặc bởi con người. Chủ đề không phải là cách duy nhất để hoàn thành công việc song song.


12

JavaScript là một luồng đơn và không đồng bộ. Ví dụ, khi bạn sử dụng XmlHttpRequest, bạn cung cấp cho nó chức năng gọi lại sẽ được thực thi không đồng bộ khi phản hồi trả về.

John Resig có một lời giải thích tốt về vấn đề liên quan về cách thức hoạt động của bộ định thời trong JavaScript .


12

Đa luồng đề cập đến nhiều hơn một hoạt động xảy ra trong cùng một quy trình. Trong khi lập trình async trải đều trên các quy trình. Ví dụ: nếu hoạt động của tôi gọi một dịch vụ web, thì luồng không cần đợi cho đến khi dịch vụ web trở lại. Ở đây chúng tôi sử dụng lập trình async cho phép luồng không chờ quá trình trong máy khác hoàn thành. Và khi nó bắt đầu nhận được phản hồi từ dịch vụ web, nó có thể làm gián đoạn luồng chính để nói rằng dịch vụ web đã hoàn tất xử lý yêu cầu. Bây giờ chủ đề chính có thể xử lý kết quả.


Tôi sẽ không đồng ý một chút. Tôi đã viết một máy chủ HTTP đơn luồng xử lý nhiều yêu cầu đồng thời bằng cách sử dụng hoàn thành IO async. Async không yêu cầu mọi thứ xảy ra trong nhiều đường thực thi, điều đó chỉ có nghĩa là nhiều luồng tính toán có thể chồng lấp. Một cách khác để xem xét nó là trên một hệ điều hành đơn luồng, tôi có thể có 2 tiến trình chạy "đồng thời". Từ quan điểm của mỗi quá trình, chúng đang chạy đồng bộ. Tuy nhiên, từ quan điểm của hệ điều hành, nó đang hoạt động không đồng bộ.
Mike

11

Windows luôn có quá trình xử lý không đồng bộ kể từ thời điểm không ưu tiên (phiên bản 2.13, 3.0, 3.1, v.v.) bằng cách sử dụng vòng lặp thông báo, trước khi hỗ trợ các luồng thực. Vì vậy, để trả lời câu hỏi của bạn, không, không cần thiết phải tạo một luồng để thực hiện xử lý không đồng bộ.


@dmckee - thật thú vị khi các hệ thống khác nhau phát triển theo cách cư xử tương tự nhau.
Otávio Décio

8

Các cuộc gọi không đồng bộ thậm chí không cần phải xảy ra trên cùng một hệ thống / thiết bị như cuộc gọi gọi. Vì vậy, nếu câu hỏi là, một cuộc gọi không đồng bộ có yêu cầu một luồng trong quy trình hiện tại không, câu trả lời là không. Tuy nhiên, phải có một luồng thực thi ở đâu đó xử lý yêu cầu không đồng bộ.

Chủ đề thực hiện là một thuật ngữ mơ hồ. Trong một hệ thống tác vụ hợp tác như Macintosh ban đầu và HĐH Windows, luồng thực thi có thể chỉ đơn giản là cùng một quy trình khiến yêu cầu chạy một ngăn xếp khác, con trỏ lệnh, v.v ... Tuy nhiên, khi mọi người thường nói về các cuộc gọi không đồng bộ , chúng thường có nghĩa là các cuộc gọi được xử lý bởi một luồng khác nếu đó là quy trình nội bộ (nghĩa là trong cùng một quy trình) hoặc bởi một quy trình khác nếu đó là quy trình liên.

Lưu ý rằng giao tiếp giữa quá trình (hoặc quá trình) (IPC) thường được khái quát hóa để bao gồm giao tiếp nội bộ, vì các kỹ thuật khóa và đồng bộ hóa dữ liệu thường giống nhau bất kể các luồng xử lý riêng biệt chạy trong quá trình nào.


7

Một số hệ thống cho phép bạn tận dụng đồng thời trong kernel cho một số cơ sở sử dụng các cuộc gọi lại. Đối với một trường hợp khá mơ hồ, các cuộc gọi lại IO không đồng bộ đã được sử dụng để triển khai các máy chủ internet không chặn trở lại trong những ngày đa nhiệm không được ưu tiên của Mac System 6-8.

Bằng cách này, bạn có các luồng thực thi đồng thời "trong" chương trình của bạn mà không có các luồng như vậy .


5

Không đồng bộ chỉ có nghĩa là bạn không chặn chương trình của mình chờ đợi một cái gì đó (chức năng gọi, thiết bị, v.v.) kết thúc. Nó có thể được thực hiện trong một luồng riêng biệt, nhưng cũng thường sử dụng một luồng chuyên dụng cho các tác vụ đồng bộ và giao tiếp thông qua một số loại hệ thống sự kiện và do đó đạt được hành vi giống như không đồng bộ.

Có các ví dụ về các chương trình không đồng bộ đơn luồng. Cái gì đó như:

...do something
...send some async request
while (not done)
    ...do something else
    ...do async check for results

2

Bản chất của các cuộc gọi không đồng bộ là ở chỗ, nếu bạn muốn ứng dụng tiếp tục chạy trong khi cuộc gọi đang diễn ra, bạn sẽ cần phải tạo ra một luồng mới hoặc ít nhất là sử dụng một luồng khác mà bạn đã tạo chỉ nhằm mục đích xử lý các cuộc gọi lại không đồng bộ.

Đôi khi, tùy thuộc vào tình huống, bạn có thể muốn gọi một phương thức không đồng bộ nhưng làm cho nó trở nên đồng bộ với người dùng (nghĩa là chặn cho đến khi phương thức không đồng bộ báo hiệu rằng nó đã hoàn thành). Điều này có thể đạt được thông qua các API Win32 như WaitForSingleObject .


Điều này đúng trên một số hệ thống, nhưng không phải tất cả. Unix không yêu cầu bạn sinh ra hoặc sử dụng một luồng khác, trừ khi bạn gọi kernel là một luồng khác, mà tôi cho là một cách để xem xét nó.
Craig S

Điều này cũng không đúng trên Windows. Ví dụ, I / O chồng chéo là không đồng bộ.
Jason Orendorff
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.