Một coroutine là gì?


204

Một coroutine là gì? Làm thế nào chúng liên quan đến đồng thời?


2
Mã đồng thời không nhất thiết phải chạy "song song" (chúng ta không giới thiệu các thuật ngữ mới).
lucid_dreamer

2
Tôi đã viết một thư viện coroutine với tiêu chuẩn C, hỗ trợ các tin nhắn GUI select / poll / eplll / kqueue / iocp / Win cho Linux, BSD và Windows. Đây là một dự án nguồn mở trong github.com/acl-dev/libfiber . Lời khuyên sẽ được chào đón.
ShuXin Trịnh

Thêm thông tin thú vị tại đây: stackoverflow.com/q/16951904/14357
tiêu

Tôi có thể tưởng tượng câu hỏi này sẽ bị hạ cấp nếu nó được hỏi ở thời đại hiện tại. Không chắc chắn tại sao có sự khác biệt lớn về nhận thức cộng đồng so với trước đây?
tnkh

một coroutine là một chức năng có thể đình chỉ việc thực hiện trước khi quay trở lại và nó có thể gián tiếp chuyển quyền kiểm soát sang một coroutine khác trong một thời gian.
Fraanzadeh.sd

Câu trả lời:


138

Coroutines và concurrency phần lớn là trực giao. Coroutines là một cấu trúc điều khiển chung, theo đó kiểm soát dòng chảy được hợp tác thông qua giữa hai thói quen khác nhau mà không quay trở lại.

Câu lệnh 'suất' trong Python là một ví dụ hay. Nó tạo ra một coroutine. Khi gặp 'năng suất', trạng thái hiện tại của chức năng được lưu và điều khiển được trả về chức năng gọi. Sau đó, chức năng gọi có thể chuyển thực thi trở lại chức năng cho năng suất và trạng thái của nó sẽ được khôi phục đến điểm gặp phải 'năng suất' và việc thực thi sẽ tiếp tục.


19
Sự khác biệt giữa việc gọi một chức năng trực tiếp và năng suất từ ​​một coroutine với việc bọc chức năng này vào coroutine này là gì?
Ming Li

3
Có lẽ tốt hơn để giải thích rằng hai khái niệm này không thực sự "trực giao" trong bối cảnh này. Bạn chắc chắn có thể vẽ làm thế nào hai khái niệm tương tự nhau. Ý tưởng vượt qua sự kiểm soát giữa hai hoặc nhiều thứ rất giống nhau.
steviejay

8
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.<- Đây đồng thời. Từ bạn đang tìm kiếm là song song.
Adam Arold

@steviejay orthogonal = Not similar to each other?
tonix

1
@tonix Tôi được bảo orthogonallà "độc lập với nhau".
Rick

77

Từ Lập trình trong Lua , Coroutinesphần "":

Một coroutine tương tự như một luồng (theo nghĩa đa luồng): nó là một dòng thực thi, với ngăn xếp riêng, các biến cục bộ của riêng nó và con trỏ lệnh riêng của nó; nhưng nó chia sẻ các biến toàn cầu và hầu hết mọi thứ khác với các coroutines khác. Sự khác biệt chính giữa các luồng và coroutines là, về mặt khái niệm (hoặc theo nghĩa đen, trong một máy đa bộ xử lý), một chương trình với các luồng chạy một số luồng song song. Mặt khác, các coroutines là hợp tác: tại bất kỳ thời điểm nào, một chương trình với các coroutines chỉ chạy một trong các coroutine của nó, và coroutine này chỉ đình chỉ thực hiện khi nó yêu cầu đình chỉ rõ ràng.

Vì vậy, vấn đề là: Coroutines là "hợp tác". Ngay cả trong hệ thống đa lõi, chỉ có một coroutine chạy tại bất kỳ thời điểm nào (nhưng nhiều luồng có thể chạy song song). Không có sự ngăn chặn giữa các coroutine, coroutine đang chạy phải từ bỏ việc thực hiện một cách rõ ràng.

Đối với " concurrency", bạn có thể tham khảo slide của Rob Pike :

Đồng thời là thành phần của các tính toán thực thi độc lập.

Vì vậy, trong quá trình hành quyết của coroutine A, nó chuyển giao quyền kiểm soát cho coroutine B. Sau một thời gian, coroutine B chuyển quyền kiểm soát trở lại coroutine A. Vì có sự phụ thuộc giữa các coroutine và chúng phải chạy song song, vì vậy hai coroutine không đồng thời .


6
Quân đoàn không thực hiện độc lập. Họ thay phiên nhau, từng người chờ người kia làm một phần công việc. Họ chủ động phối hợp với nhau. Điều đó trái ngược với định nghĩa đồng thời của Rob Pikes.
Erick G. Hagstrom

2
@ ErickG.Hagstrom: Mặc dù chúng không thực thi độc lập, logic của mọi coroutine có thể độc lập, phải không? Nếu đúng, nó giống như một hệ điều hành không được ưu tiên chạy trên CPU một lõi, một quy trình phải từ bỏ CPU để cho các tác vụ khác chạy.
Nan Xiao

6
Có một sự khác biệt giữa việc từ bỏ CPU để cho một số tác vụ khác chạy và nói với một số quy trình cụ thể khác mà đã đến lúc thực hiện. Quân đoàn làm sau. Điều đó không độc lập theo bất kỳ ý nghĩa nào.
Erick G. Hagstrom

7
@ChrisClark Tôi đồng ý với bạn. Quân đoàn là đồng thời. Dưới đây là một số trích dẫn từ wikipedia: Coroutines rất giống với chủ đề. Tuy nhiên, coroutines được đa nhiệm hợp tác, trong khi các chủ đề thường được đa nhiệm ưu tiên. Điều này có nghĩa là họ cung cấp đồng thời nhưng không song song .
smwikipedia

3
Và: Đa nhiệm hợp tác, còn được gọi là đa nhiệm không ưu tiên, là một kiểu đa nhiệm máy tính trong đó hệ điều hành không bao giờ bắt đầu chuyển đổi ngữ cảnh từ quy trình đang chạy sang quy trình khác. Thay vào đó, các quy trình tự nguyện mang lại kiểm soát định kỳ hoặc khi không hoạt động hoặc bị chặn một cách hợp lý để cho phép nhiều ứng dụng được chạy đồng thời.
smwikipedia

47

Tôi thấy hầu hết các câu trả lời quá kỹ thuật mặc dù đó là một câu hỏi kỹ thuật. Tôi đã có một thời gian khó khăn để cố gắng hiểu quá trình coroutine. Tôi nhận được nó nhưng sau đó tôi không nhận được nó cùng một lúc.

Tôi thấy câu trả lời này ở đây rất hữu ích:

https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9

Để trích dẫn từ Idan Arye:

Để xây dựng câu chuyện của bạn, tôi sẽ đặt nó như thế này:

Bạn bắt đầu xem phim hoạt hình, nhưng đó là phần giới thiệu. Thay vì xem phần giới thiệu, bạn chuyển sang trò chơi và vào sảnh trực tuyến - nhưng nó cần 3 người chơi và chỉ có bạn và em gái của bạn ở trong đó. Thay vì chờ người chơi khác tham gia, bạn chuyển sang bài tập về nhà và trả lời câu hỏi đầu tiên. Câu hỏi thứ hai có liên kết đến video YouTube mà bạn cần xem. Bạn mở nó - và nó bắt đầu tải. Thay vì chờ nó tải, bạn quay lại phim hoạt hình. Phần giới thiệu đã kết thúc, vì vậy bạn có thể xem. Bây giờ có quảng cáo - nhưng trong khi đó, một người chơi thứ ba đã tham gia để bạn chuyển sang trò chơi Và cứ thế ...

Ý tưởng là bạn không chỉ chuyển đổi các nhiệm vụ thực sự nhanh chóng để làm cho nó trông giống như bạn đang làm mọi thứ cùng một lúc. Bạn sử dụng thời gian bạn đang chờ đợi điều gì đó xảy ra (IO) để làm những việc khác đòi hỏi sự chú ý trực tiếp của bạn.

Chắc chắn kiểm tra các liên kết, có nhiều hơn nữa mà tôi không thể trích dẫn tất cả mọi thứ.


6
Rất đơn giản và minh họa thẳng. +1 cho điều này.
Taslim Oseni

minh họa tuyệt vời. Tôi đã xây dựng một câu chuyện tương tự - với việc đứng xếp hàng chờ đợi để thu thập một gói. Nhưng hôm nay, bạn thực tế hơn nhiều, ai đứng xếp hàng khi có giao hàng tại cửa? Lol
apolak

1
Đó là lời giải thích tuyệt vời. Từ trích dẫn chính nó, nó là siêu rõ ràng.
Farruh Habibullaev

15

Coroutine tương tự như chương trình con / chủ đề. Sự khác biệt là một khi người gọi gọi một chương trình con / luồng, nó sẽ không bao giờ quay trở lại chức năng của người gọi. Nhưng một coroutine có thể quay trở lại người gọi sau khi thực thi một vài đoạn mã cho phép người gọi thực thi một số mã của chính nó và quay trở lại điểm coroutine nơi nó dừng thực thi và tiếp tục từ đó. I E. Một coroutine có nhiều điểm vào và ra


Nó không quá giống với các luồng - chạy độc lập và đồng thời (tách các lõi song song). Ngoài ra, so sánh chương trình con thất bại theo nghĩa là có nhiều đường thực hiện độc lập và chúng không trả về kết quả cho nhau.
javadba

11
  • Coroutines là các tính năng tuyệt vời có sẵn trong Ngôn ngữ Kotlin
  • Coroutines là một cách mới để viết mã không đồng bộ, không chặn (và nhiều hơn nữa)
  • Coroutine là chủ đề trọng lượng nhẹ. Một luồng trọng lượng nhẹ có nghĩa là nó không ánh xạ trên luồng gốc, do đó nó không yêu cầu chuyển ngữ cảnh trên bộ xử lý, vì vậy chúng nhanh hơn.
  • nó không ánh xạ trên chủ đề gốc
  • Coroutines và các chủ đề cả hai là đa nhiệm. Nhưng sự khác biệt là các luồng được quản lý bởi HĐH và coroutines bởi người dùng.

Về cơ bản, có hai loại Coroutines:

  1. Không có chồng
  2. Xếp chồng

Kotlin thực hiện các coroutines stackless - điều đó có nghĩa là các coroutine không có stack riêng, vì vậy chúng không ánh xạ trên luồng gốc.

Đây là các chức năng để bắt đầu coroutine:

launch{}

async{}

Bạn có thể tìm hiểu thêm từ đây:

https://www.kotlindevelopment.com/deep-dive-coroutines/

https://blog.mindork.com/what-are-coroutines-in-kotlin-bf4fecd476e9


1
Câu trả lời tốt! Hữu ích cho các nhà phát triển Kotlin và Android.
Malwinder Singh

5

Một lưu ý khác, trong geventthư viện python là một coroutinethư viện mạng dựa trên nó cung cấp cho bạn các tính năng giống như các yêu cầu mạng không đồng bộ, mà không cần chi phí tạo và hủy các luồng. Các coroutinethư viện sử dụng là greenlet.


2

Từ Python Coroutine :

Việc thực thi các xác chết Python có thể bị đình chỉ và tiếp tục tại nhiều điểm (xem coroutine). Bên trong phần thân của hàm coroutine, các định danh chờ đợi và không đồng bộ trở thành các từ khóa dành riêng; đang chờ các biểu thức, async for và async with chỉ có thể được sử dụng trong các thân hàm coroutine.

Từ quân đoàn (C ++ 20)

Một coroutine là một chức năng có thể đình chỉ thực hiện để được nối lại sau này . Quân đoàn không có chồng: họ đình chỉ thực hiện bằng cách quay lại người gọi. Điều này cho phép mã tuần tự thực thi không đồng bộ (ví dụ: để xử lý I / O không chặn mà không cần gọi lại rõ ràng) và cũng hỗ trợ các thuật toán trên các chuỗi vô hạn được tính toán lười biếng và các cách sử dụng khác.

So sánh với câu trả lời của người khác:

Theo tôi, phần sau được nối lại là một sự khác biệt cốt lõi, giống như @ Twinkle's.
Mặc dù nhiều lĩnh vực của tài liệu vẫn đang được tiến hành, tuy nhiên, phần này tương tự như hầu hết câu trả lời, ngoại trừ của @Nan Xiao

Mặt khác, các coroutines là hợp tác: tại bất kỳ thời điểm nào, một chương trình với các coroutines chỉ chạy một trong các coroutine của nó, và coroutine này chỉ đình chỉ thực hiện khi nó yêu cầu đình chỉ rõ ràng.

Vì nó được trích dẫn từ Chương trình ở Lua, có thể nó liên quan đến ngôn ngữ (hiện tại không quen thuộc với Lua), nên không phải tất cả tài liệu đều đề cập đến một phần duy nhất .

Mối quan hệ với đồng thời:
Có một phần "Thi hành" của Coroutines (C ++ 20). Xin được trích dẫn ở đây.
Bên cạnh các chi tiết, có một số tiểu bang.

When a coroutine begins execution  
When a coroutine reaches a suspension point  
When a coroutine reaches the co_return statement  
If the coroutine ends with an uncaught exception  
When the coroutine state is destroyed either because it terminated via co_return or uncaught exception, or because it was destroyed via its handle 

như nhận xét từ @Adam Arold dưới câu trả lời của @ user217714. Đó là sự đồng thời.
Nhưng nó khác với đa luồng. từ std :: chủ đề

Chủ đề cho phép nhiều chức năng để thực hiện đồng thời. Các luồng bắt đầu thực thi ngay khi xây dựng đối tượng luồng liên quan (đang chờ xử lý bất kỳ độ trễ lập lịch của hệ điều hành), bắt đầu từ hàm cấp cao nhất được cung cấp dưới dạng đối số của hàm tạo. Giá trị trả về của hàm cấp cao nhất bị bỏ qua và nếu nó chấm dứt bằng cách ném một ngoại lệ, std :: terminating được gọi. Hàm cấp cao nhất có thể truyền đạt giá trị trả về của nó hoặc một ngoại lệ cho người gọi thông qua std :: hứa hoặc bằng cách sửa đổi các biến được chia sẻ (có thể yêu cầu đồng bộ hóa, xem std :: mutex và std :: nguyên tử)

Vì nó đồng thời, nó hoạt động như đa luồng, đặc biệt là khi chờ đợi là không thể tránh khỏi (từ góc độ hệ điều hành), đó cũng là lý do khiến nó khó hiểu.


1

Một coroutine là một loại chương trình con đặc biệt. Thay vì mối quan hệ chủ-chủ giữa người gọi và chương trình con được gọi là tồn tại với các chương trình con thông thường, người gọi và người được gọi là coroutines là công bằng hơn.

  • Một coroutine là một chương trình con có nhiều mục và tự điều khiển chúng - được hỗ trợ trực tiếp trong Lua

  • Cũng được gọi là điều khiển đối xứng: người gọi và người được gọi là coroutines trên cơ sở bình đẳng hơn

  • Một cuộc gọi coroutine được đặt tên là một sơ yếu lý lịch

  • Sơ yếu lý lịch đầu tiên của một coroutine là bắt đầu, nhưng các cuộc gọi tiếp theo nhập vào điểm ngay sau câu lệnh được thực hiện cuối cùng trong coroutine

  • Quân đoàn liên tục nối lại nhau, có thể là mãi mãi

  • Các quân đoàn cung cấp việc thực hiện đồng thời các đơn vị chương trình (các coroutines); thực hiện của họ là xen kẽ, nhưng không chồng chéo

Ví dụ 1 Ví dụ2


1

Tôi tìm thấy một lời giải thích từ liên kết này là khá thẳng về phía trước. Không ai trong số những câu trả lời đó cố gắng giải thích sự tương tranh và song song ngoại trừ gạch đầu dòng cuối cùng trong câu trả lời này .

  1. đồng thời (chương trình) là gì?

được trích dẫn từ "lập trình Erlang", bởi Joe Armstrong, huyền thoại:

một chương trình đồng thời có thể chạy tiềm năng nhanh hơn trên một máy tính song song.

  • một chương trình đồng thời là một chương trình được viết bằng ngôn ngữ lập trình đồng thời. Chúng tôi viết các chương trình đồng thời vì lý do hiệu suất, khả năng mở rộng hoặc khả năng chịu lỗi.

  • một ngôn ngữ lập trình đồng thời là một ngôn ngữ có cấu trúc ngôn ngữ rõ ràng để viết các chương trình đồng thời. Các cấu trúc này là một phần không thể thiếu của ngôn ngữ lập trình và hoạt động theo cùng một cách trên tất cả các hệ điều hành.

  • một máy tính song song là một máy tính có một số đơn vị xử lý (CPU hoặc lõi) có thể chạy cùng một lúc.

Vì vậy đồng thời không giống như song song. Bạn vẫn có thể viết các chương trình đồng thời trên một máy tính lõi đơn. Bộ lập lịch chia sẻ thời gian sẽ khiến bạn cảm thấy chương trình của mình đang chạy đồng thời.

Chương trình đồng thời có khả năng chạy song song trong một máy tính song song nhưng không được bảo đảm . Hệ điều hành chỉ có thể cung cấp cho bạn một lõi để chạy chương trình của bạn.

Do đó, đồng thời là một mô hình phần mềm từ một chương trình đồng thời không có nghĩa là chương trình của bạn có thể chạy song song về mặt vật lý.

  1. coroutine và đồng thời

Từ ngữ coroutine nghiêm túc bao gồm hai từ: thói quen (hợp tác) và thói quen trực tuyến (chức năng).

a. nó có đạt được sự tương tranh hay song song không?

Để đơn giản, hãy thảo luận về nó trên một máy tính lõi đơn .

Đồng thời đạt được bằng cách chia sẻ thời gian từ hệ điều hành. Một luồng thực thi mã của nó trong các khung thời gian được chỉ định trên lõi CPU. Nó có thể được hệ điều hành ưu tiên. Nó cũng có thể mang lại quyền kiểm soát cho hệ điều hành.

Mặt khác, một coroutine mang lại quyền kiểm soát cho một coroutine khác trong luồng, không phải cho hệ điều hành. Vì vậy, tất cả các coroutines trong một luồng vẫn khai thác khung thời gian cho luồng đó mà không thu được lõi CPU cho các luồng khác do HĐH quản lý.

Do đó, bạn có thể nghĩ về coroutine đạt được chia sẻ thời gian bởi người dùng không phải bởi hệ điều hành (hoặc bán song song). Các coroutines chạy trên cùng một lõi được gán cho luồng chạy các coroutines đó.

Coroutine có đạt được sự song song không? Nếu đó là mã giới hạn CPU, thì không. Giống như chia sẻ thời gian, nó khiến bạn cảm thấy chúng chạy song song nhưng các lần thực hiện của chúng được xen kẽ không chồng chéo. Nếu nó bị ràng buộc IO, vâng, nó đạt được song song bởi phần cứng (thiết bị IO) không phải bởi mã của bạn.

b. sự khác biệt với chức năng gọi?

nhập mô tả hình ảnh ở đây

Như pic cho thấy, nó không cần phải gọi returnđể chuyển đổi điều khiển. Nó có thể mang lại mà không có return. Một coroutine lưu và chia sẻ trạng thái trên khung chức năng hiện tại (ngăn xếp). Vì vậy, nó nhẹ hơn nhiều so với chức năng vì bạn không phải lưu các thanh ghi và biến cục bộ để xếp chồng và tua lại ngăn xếp cuộc gọi khi call ret.


0

Tôi sẽ mở rộng câu trả lời của @ user21714. Quân đoàn là những con đường thực thi độc lập không thể chạy đồng thời. Chúng phụ thuộc vào bộ điều khiển - ví dụ pythonthư viện bộ điều khiển - để xử lý chuyển đổi giữa các đường dẫn này. Nhưng để làm việc này, các coroutines cần phải gọi yieldhoặc các cấu trúc tương tự cho phép tạm dừng thực thi.

Thay vào đó, các luồng đang chạy trên các tài nguyên tính toán độc lập và song song với nhau. Vì chúng ở trên các tài nguyên khác nhau, không cần phải gọi năng suất để cho phép các đường dẫn thực hiện khác được tiến hành.

Bạn có thể thấy hiệu ứng này bằng cách bắt đầu một chương trình đa luồng - ví dụ: một jvmứng dụng - trong đó tất cả tám core i7lõi siêu phân luồng của bạn được sử dụng: bạn có thể thấy mức sử dụng 797% trong Activity Monitorhoặc Top. Thay vào đó khi chạy một pythonchương trình thông thường - thậm chí một chương trình có coroutineshoặc python threading- việc sử dụng sẽ đạt tối đa 100%. Tức là một siêu máy.

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.