Sự khác biệt giữa coroutine và tiếp tục và máy phát điện là gì?
Sự khác biệt giữa coroutine và tiếp tục và máy phát điện là gì?
Câu trả lời:
Tôi sẽ bắt đầu với máy phát điện, xem chúng là trường hợp đơn giản nhất. Như @zvolkov đã đề cập, chúng là các hàm / đối tượng có thể được gọi liên tục mà không trả về, nhưng khi được gọi sẽ trả về (nhường) một giá trị và sau đó tạm dừng thực thi. Khi họ được gọi lại, họ sẽ bắt đầu từ nơi họ bị đình chỉ hành quyết lần cuối và làm lại việc của họ.
Một máy phát điện về cơ bản là một coroutine (không đối xứng). Sự khác biệt giữa coroutine và máy phát điện là coroutine có thể chấp nhận các đối số sau khi được gọi ban đầu, trong khi máy phát điện thì không thể.
Có một chút khó khăn khi đưa ra một ví dụ tầm thường về nơi bạn sử dụng coroutines, nhưng đây là nỗ lực tốt nhất của tôi. Lấy mã Python này (tạo thành) làm ví dụ.
def my_coroutine_body(*args):
while True:
# Do some funky stuff
*args = yield value_im_returning
# Do some more funky stuff
my_coro = make_coroutine(my_coroutine_body)
x = 0
while True:
# The coroutine does some funky stuff to x, and returns a new value.
x = my_coro(x)
print x
Một ví dụ về nơi coroutines được sử dụng là lexers và trình phân tích cú pháp. Không có coroutines trong ngôn ngữ hoặc được mô phỏng bằng cách nào đó, mã lexing và phân tích cú pháp cần phải được trộn lẫn với nhau mặc dù chúng thực sự là hai mối quan tâm riêng biệt. Nhưng bằng cách sử dụng coroutine, bạn có thể tách mã lexing và phân tích cú pháp.
(Tôi sẽ tìm hiểu sự khác biệt giữa các coroutine đối xứng và bất đối xứng. Chỉ cần nói rằng chúng tương đương nhau, bạn có thể chuyển đổi từ cái này sang cái khác, và coroutines không đối xứng - giống như máy phát điện - là dễ hiểu hơn. Tôi đã phác thảo cách người ta có thể triển khai các coroutines không đối xứng trong Python.)
Tiếp tục là những con thú khá đơn giản. Tất cả chúng là, là các hàm đại diện cho một điểm khác trong chương trình, nếu bạn gọi nó, sẽ khiến việc thực thi tự động chuyển sang điểm mà hàm đại diện. Bạn sử dụng các phiên bản rất hạn chế của chúng mỗi ngày mà không nhận ra. Các ngoại lệ, ví dụ, có thể được coi là một loại tiếp tục từ trong ra ngoài. Tôi sẽ cung cấp cho bạn một ví dụ mã giả dựa trên Python về sự tiếp nối.
Giả sử Python có một hàm được gọi callcc()
và hàm này có hai đối số, đầu tiên là hàm và thứ hai là danh sách các đối số để gọi nó với. Hạn chế duy nhất đối với chức năng đó là đối số cuối cùng cần có sẽ là một chức năng (sẽ là sự tiếp tục hiện tại của chúng tôi).
def foo(x, y, cc):
cc(max(x, y))
biggest = callcc(foo, [23, 42])
print biggest
Điều gì sẽ xảy ra là callcc()
lần lượt gọi foo()
với phần tiếp theo hiện tại ( cc
), nghĩa là một tham chiếu đến điểm trong chương trình callcc()
được gọi. Khi foo()
gọi tiếp tục hiện tại, về cơ bản giống như yêu callcc()
cầu trả về với giá trị mà bạn gọi là tiếp tục hiện tại và khi thực hiện điều đó, nó sẽ quay trở lại ngăn xếp đến nơi tiếp tục hiện tại được tạo, tức là khi bạn gọi callcc()
.
Kết quả của tất cả những điều này sẽ là biến thể Python giả định của chúng tôi sẽ in '42'
.
Tôi hy vọng điều đó có ích, và tôi chắc rằng lời giải thích của tôi có thể được cải thiện khá nhiều!
Coroutine là một trong một số thủ tục thay phiên nhau thực hiện công việc của họ và sau đó tạm dừng để kiểm soát các coroutine khác trong nhóm.
Tiếp tục là một "con trỏ tới một hàm" mà bạn chuyển đến một số thủ tục, để được thực thi ("tiếp tục với") khi thủ tục đó được thực hiện.
Trình tạo (trong .NET) là một cấu trúc ngôn ngữ có thể phun ra một giá trị, "tạm dừng" thực thi phương thức và sau đó tiến hành từ cùng một điểm khi được yêu cầu giá trị tiếp theo.
Trong phiên bản mới hơn của Python, bạn có thể gửi các giá trị cho Trình tạo generator.send()
, điều này làm cho Trình tạo python phát triển hiệu quả.
Sự khác biệt chính giữa python Generator và trình tạo khác, như greenlet, là trong python, bạn yield value
chỉ có thể quay lại với người gọi. Khi ở trong greenlet, target.switch(value)
có thể đưa bạn đến một coroutine mục tiêu cụ thể và mang lại một giá trị nơi mà target
nó sẽ tiếp tục chạy.
yield
cuộc gọi phải ở cùng một chức năng, được gọi là "Trình tạo". Bạn không thể yield
từ một hàm phụ, đó là lý do tại sao Python được gọi là semi-coroutines , trong khi Lua có các coroutines không đối xứng . (Có những đề xuất để tuyên truyền sản lượng, nhưng tôi nghĩ rằng những điều đó chỉ làm