Năng suất từ ​​coroutine Python

Đối với công việc tư vấn mà tôi đã làm, tôi đã sử dụng python asyncio và hiểu được khó khăn trong cú pháp đơn giản của nó. Phải mất khá nhiều thời gian để đọc blog và các ví dụ để hiểu cách thức hoạt động của nó. Chủ đề này áp đảo vì lịch sử của nó với các trình tạo / cú pháp coroutine cũ hơn và yêu cầu một số kiến ​​​​thức cơ bản về một số khái niệm để hiểu rõ hơn

Tôi muốn chia sẻ những điều mình học được, điều này sẽ giúp hiểu được các nguyên tắc cơ bản cốt lõi với các định nghĩa ngắn gọn và các ví dụ mã đơn giản để giúp làm việc với asyncio dễ dàng hơn. . )

chủ đề

1) Giới thiệu
2) Lịch sử & Cách thức hoạt động
3) Tóm tắt
4) API HTTP đơn giản

1. Giới thiệu

Sau đây là tổng quan ngắn gọn về các thuật ngữ được sử dụng trong các chủ đề

Đồng thời vs Song song

  • Đồng thời — khả năng thực thi hai hoặc nhiều tác vụ có thể bắt đầu, chạy và hoàn thành trong các khoảng thời gian chồng chéo (có thể là thực thi song song thực sự trên đa lõi hoặc cắt thời gian trên một máy lõi đơn với sự trợ giúp của các luồng)
  • Tính song song —là về việc thực hiện các tác vụ song song cùng một lúc. (e. g. , ít nhất hai luồng đang thực thi đồng thời)
  • Chủ đề - Chủ đề giúp thực thi nhiều tác vụ giúp đạt được Đồng thời/Song song. Trong một quy trình python duy nhất, không thể xử lý song song luồng do Khóa phiên dịch toàn cầu (triển khai CPython). GIL là một cơ chế mutex ngăn nhiều luồng thực thi đồng thời trên các đối tượng Python. Vì vậy, chỉ một luồng có thể thực thi tại một thời điểm trong số nhiều luồng trong quy trình python
  • Đa quy trình — Cần có nhiều quy trình python để đạt được tính song song. gói đa xử lý cung cấp cả đồng thời cục bộ và từ xa, hỗ trợ GIL một cách hiệu quả bằng cách sử dụng các quy trình con thay vì các luồng

Đồng bộ hóa và không đồng bộ

Đồng bộ hóa/Không đồng bộ là về cách tính toán/tác vụ được thực hiện trong ngữ cảnh của một Chủ đề duy nhất

  • Đồng bộ hóa — chặn thực thi tác vụ. Việc thực thi tính toán/tác vụ bởi một Chủ đề (cpu) bị chặn/đang chờ một thao tác (IO) hoàn thành.
    e. g. một luồng duy nhất xử lý yêu cầu http thực hiện cuộc gọi DB và đợi phản hồi db trả về phản hồi http, sau đó nhận yêu cầu http tiếp theo.
  • Không đồng bộ — thực hiện đồng thời các tác vụ. Nhiều tác vụ có thể bắt đầu, tạm dừng và hoàn thành độc lập với nhau được thực hiện bởi một luồng duy nhất. Các tác vụ không đồng bộ không chặn các hoạt động thường chờ IO. Nó chủ yếu hữu ích cho các trường hợp sử dụng liên kết IO (đĩa/mạng) vì CPU có thể được sử dụng cho các mục đích khác trong khi chúng tôi đang chờ IO. coroutines trong python giúp đạt được điều này.
    e. g. một luồng xử lý yêu cầu http thực hiện cuộc gọi DB và tạm dừng tác vụ hiện tại cho phản hồi DB. Cùng một chủ đề nhận một yêu cầu mới và bắt đầu xử lý.

2) Lịch sử & Cách thức hoạt động?

vòng lặp

Trình lặp là các đối tượng có thể được lặp lại (sử dụng __iter__ và __next__) một cách lười biếng

list = [1, 2]
iterator = iter(list)
print(next(iterator))
print(iterator.__next__())
print(next(iterator))
# Output:
1
2
Raise StopIteration exception since no items to iterate

máy phát điện

Trình tạo (Thông thường) là các trình lặp giúp đơn giản hóa sự phức tạp trong việc xây dựng trình lặp logic tùy chỉnh. Nó tạo ra một giá trị nhanh chóng cho mỗi lần chạy (ví dụ:. , nhà sản xuất lười biếng)

Làm thế nào để tạo ra ?

trình tạo là bất kỳ chức năng bình thường nào với câu lệnh

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
9 thay vì câu lệnh
def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
0

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
9 là một từ khóa được sử dụng giống như
def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
0, ngoại trừ hàm sẽ trả về một trình tạo. Câu lệnh
import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
9 tạm dừng chức năng lưu tất cả các trạng thái của nó và sau đó tiếp tục từ trạng thái cuối cùng trong các lệnh gọi liên tiếp (tham khảo thêm tại đây)

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped

Đối tượng trình tạo ví dụ tương tự có thể được tương tác với vòng lặp 'for' vì nó là một trình vòng lặp

def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...

Chúng ta có thể tạo đường ống dẫn tương tự như đường ống Unix

________số 8

PEP-380, (

def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
4 được giới thiệu để đơn giản hóa đường ống của máy phát điện)

  • Bổ sung
    def magic_pot(start=1, end=1000):
    while True:
    yield random.randint(start, end)
    gen = magic_pot()
    for a in gen:
    print(a)
    # Output: prints numbers without stopping
    569
    ...
    5 trong Python 3. 3 giúp tái cấu trúc các trình tạo cũng như xâu chuỗi chúng lại với nhau dễ dàng hơn
import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
1

quy trình

Coroutines là các thành phần chương trình máy tính tổng quát hóa các chương trình con cho đa nhiệm không ưu tiên, bằng cách cho phép nhiều điểm vào để tạm dừng và tiếp tục thực thi tại các vị trí nhất định

Coroutines giúp đạt được đa nhiệm/đồng thời hợp tác. Chúng là các chức năng/tác vụ giúp thực thi đồng thời bằng cách có khả năng tạm dừng và tiếp tục các tác vụ trong một luồng. (e. g. , I/O không đồng bộ và các dạng lập trình hướng sự kiện hoặc đa nhiệm hợp tác khác)

Phát triển thành “Generator Coroutine”

Trình tạo không có khả năng chấp nhận các đối số trong khi thực thi, điều này khiến cho việc kiểm soát luồng logic bên trong hàm trình tạo trở nên khó khăn (e. g. một coroutine A chờ phản hồi từ một cuộc gọi http khác coroutine B. Coroutine A tạm dừng -> Coroutine B Http Complete -> Tiếp tục Coroutine A (phản hồi http từ Coroutine B))

Trình tạo đã được phát triển để hỗ trợ các coroutine như khả năng sử dụng PEP-342 (Python 2. 5), giúp truyền tham số cho trình tạo để kiểm soát luồng thực thi. Điều này cuối cùng đã giúp đạt được các khả năng của coroutine, các hình thức đa nhiệm hợp tác khác

PEP-342

Các hàm tạo của Python gần như là các coroutines — nhưng không hoàn toàn — ở chỗ chúng cho phép tạm dừng thực thi để tạo ra một giá trị, nhưng không cung cấp các giá trị hoặc ngoại lệ được chuyển vào khi tiếp tục thực thi

bộ tạo không thể tạo ra quyền kiểm soát trong khi các chức năng khác đang thực thi, trừ khi các chức năng đó được thể hiện dưới dạng bộ tạo và bộ tạo bên ngoài được viết để tạo ra để đáp ứng các giá trị do bộ tạo bên trong tạo ra. Điều này làm phức tạp việc triển khai các trường hợp sử dụng thậm chí tương đối đơn giản như truyền thông không đồng bộ, bởi vì việc gọi bất kỳ chức năng nào cũng yêu cầu trình tạo chặn (i. e. không thể mang lại quyền kiểm soát), nếu không, phải thêm rất nhiều mã vòng lặp soạn sẵn xung quanh mỗi lệnh gọi hàm cần thiết

Tuy nhiên, nếu có thể chuyển các giá trị(send()) hoặc ngoại lệ vào một trình tạo tại điểm mà nó bị treo, thì một bộ lập lịch đồng quy trình đơn giản hoặc chức năng tấm bạt lò xo sẽ ​​cho phép các coroutine gọi lẫn nhau mà không bị chặn — một lợi ích to lớn cho tính năng không đồng bộ . Các ứng dụng như vậy sau đó có thể viết các đồng quy trình để thực hiện I/O ổ cắm không chặn bằng cách nhường quyền kiểm soát cho bộ lập lịch I/O cho đến khi dữ liệu được gửi hoặc có sẵn. Trong khi đó, mã thực hiện I/O sẽ đơn giản làm điều gì đó như thế này

dữ liệu = (lợi nhuận nonblocking_read(my_socket, nbytes))

để tạm dừng thực thi cho đến khi nonblocking_read() coroutine tạo ra một giá trị

Ở trên PEP đã thêm các cải tiến để thêm phương thức gửi (), ném (), đóng () cho trình tạo.

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
9 đã được thay đổi dưới dạng biểu thức và hoạt động như một công cụ giao tiếp hai chiều được giải thích trong ví dụ bên dưới

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
3

Coroutine vs Máy phát điện

Coroutine là một trình tạo tuân theo các quy ước nhất định

  • coroutine nhường quyền kiểm soát cho một coroutine khác và có thể tiếp tục thực thi từ thời điểm nó từ bỏ quyền kiểm soát
  • coroutines là người tiêu dùng dữ liệu trong khi trình tạo là nhà sản xuất dữ liệu
  • có thể gửi các giá trị tới các coroutines dựa trên trình tạo (sử dụng câu lệnh send() & (yield)) sau khi nó được khởi tạo trong khi các trình tạo thông thường không thể

AsyncIO — I/O không đồng bộ, vòng lặp sự kiện, coroutines và tác vụ

Từ tài liệu Python

Mô-đun này cung cấp cơ sở hạ tầng để viết mã đồng thời đơn luồng bằng cách sử dụng coroutines, ghép kênh truy cập I/O qua ổ cắm và các tài nguyên khác, chạy máy khách và máy chủ mạng. Chúng ta sẽ xem xét từng chủ đề dưới đây

Vòng lặp sự kiện là cốt lõi của mọi ứng dụng asyncio. Các vòng lặp sự kiện chạy các tác vụ và lệnh gọi lại không đồng bộ, thực hiện các hoạt động IO của mạng và chạy các quy trình con. Các nhà phát triển ứng dụng thường nên sử dụng các chức năng asyncio cấp cao, chẳng hạn như asyncio. run(), và hiếm khi cần tham chiếu đối tượng vòng lặp hoặc gọi các phương thức của nó

Quy trình tạo AsyncIO

Trong trăn 3. 4, coroutines dựa trên trình tạo được tạo bằng trình trang trí

def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
7 bằng thư viện mô-đun asyncio mới. Các coroutine của trình tạo Asyncio sử dụng cú pháp
def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
5 để tạm dừng coroutine

Một asyncio coroutine có thể

  • "đầu ra từ" một coroutine khác
  • “sản lượng từ” một tương lai
  • trả về một biểu thức
  • tăng ngoại lệ

Câu lệnh

def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
5 từ bỏ quyền điều khiển trở lại vòng lặp sự kiện để cho các coroutine khác thực thi

  • Cú pháp “yield from” được giới thiệu trong PEP 380, thay vì cú pháp yield ban đầu cho coroutine của trình tạo. "yield from" được sử dụng bên trong các coroutines của máy phát điện.
    def magic_pot(start=1, end=1000):
    while True:
    yield random.randint(start, end)
    gen = magic_pot()
    for a in gen:
    print(a)
    # Output: prints numbers without stopping
    569
    ...
    5iterator hoặc coroutines bản địa/trình tạo/tương lai
  • Cho phép trình tạo sử dụng “yield from” để gọi các coroutine gốc (def async) và cũng cho phép coroutine của trình tạo được gọi bởi các coroutine gốc bằng cách sử dụng biểu thức đang chờ
  • Việc sử dụng "yield" khiến chúng trở thành trình tạo/trình lặp thông thường phải được lặp lại và không hoạt động với các phương thức asyncio
import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
8

Coroutines bản địa

def read_file(file_name):
for row in open(file_name, "r"):
yield row


def read_csv_row(file_name):
for row in read_file(file_name):
yield row.split(',')


def read_csv(file_name):
for items in read_csv_row(file_name):
print("Row: " + str(items))


read_csv('test.csv')
# Output:
Row: ['col1', 'col2', 'col3\n']
Row: ['1', '2', '3\n']
Row: ['3', '4', '5']
1 từ khóa được giới thiệu kể từ Python 3. 5 giúp ngữ pháp lập trình coroutine thêm ý nghĩa và cú pháp mới nhất

  • async def trả về một đối tượng coroutine gốc. async def chức năng luôn là coroutine, ngay cả khi không có sự chờ đợi
  • Trình tạo thông thường trả về một đối tượng trình tạo
  • không đồng bộ. coroutine trả về đối tượng coroutine dựa trên trình tạo
  • các loại. coroutine trả về đối tượng coroutine dựa trên trình tạo
def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
0

chờ đợi

  • “await” nên được sử dụng với async def.
    def read_file(file_name):
    for row in open(file_name, "r"):
    yield row


    def read_csv_row(file_name):
    for row in read_file(file_name):
    yield row.split(',')


    def read_csv(file_name):
    for items in read_csv_row(file_name):
    print("Row: " + str(items))


    read_csv('test.csv')
    # Output:
    Row: ['col1', 'col2', 'col3\n']
    Row: ['1', '2', '3\n']
    Row: ['3', '4', '5']
    2 được sử dụng để lấy kết quả thực thi của một đối tượng coroutine
  • async/await tương đương mới nhất với @asyncio. coroutine/'sản lượng từ'
  • await hoạt động trên các đối tượng trình tạo/coroutines gốc và trên đối tượng có phương thức __await__ trả về một trình vòng lặp
  • Dưới vỏ bọc,
    def read_file(file_name):
    for row in open(file_name, "r"):
    yield row


    def read_csv_row(file_name):
    for row in read_file(file_name):
    yield row.split(',')


    def read_csv(file_name):
    for items in read_csv_row(file_name):
    print("Row: " + str(items))


    read_csv('test.csv')
    # Output:
    Row: ['col1', 'col2', 'col3\n']
    Row: ['1', '2', '3\n']
    Row: ['3', '4', '5']
    2 mượn triển khai từ
    def magic_pot(start=1, end=1000):
    while True:
    yield random.randint(start, end)
    gen = magic_pot()
    for a in gen:
    print(a)
    # Output: prints numbers without stopping
    569
    ...
    5 với một kiểm tra bổ sung nếu đối số của nó thực sự là một chờ đợi
  • quy trình gốc/trình tạo, tương lai, các nhiệm vụ được chờ đợi
def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
4

Các Coroutine đồng thời (async/await, @asyncio. coroutine/năng suất từ)

def magic_pot(start=1, end=1000):
while True:
yield random.randint(start, end)
gen = magic_pot()
for a in gen:
print(a)
# Output: prints numbers without stopping
569
...
5

Câu lệnh coroutine compute() “yield from” từ bỏ quyền điều khiển trở lại vòng lặp sự kiện (tạm dừng) và tiếp tục thực thi sau khi coroutine

def read_file(file_name):
for row in open(file_name, "r"):
yield row


def read_csv_row(file_name):
for row in read_file(file_name):
yield row.split(',')


def read_csv(file_name):
for items in read_csv_row(file_name):
print("Row: " + str(items))


read_csv('test.csv')
# Output:
Row: ['col1', 'col2', 'col3\n']
Row: ['1', '2', '3\n']
Row: ['3', '4', '5']
5 hoàn thành. Lưu ý rằng bản thân
def read_file(file_name):
for row in open(file_name, "r"):
yield row


def read_csv_row(file_name):
for row in read_file(file_name):
yield row.split(',')


def read_csv(file_name):
for items in read_csv_row(file_name):
print("Row: " + str(items))


read_csv('test.csv')
# Output:
Row: ['col1', 'col2', 'col3\n']
Row: ['1', '2', '3\n']
Row: ['3', '4', '5']
5 là một quy trình đăng ký và quy trình đăng ký bị chặn sẽ tiếp tục sau khi ngủ. Vòng lặp sự kiện thực thi dựa trên các coroutine có thể chạy được và thứ tự thực hiện đầu ra (t1, t2, t3) thay đổi dựa trên độ trễ trong ví dụ

Vòng lặp sự kiện

  • Vòng lặp sự kiện sử dụng lập lịch hợp tác, nghĩa là vòng lặp sự kiện chạy một Tác vụ tại một thời điểm. Trong khi một Tác vụ đang chờ hoàn thành Tương lai, vòng lặp sự kiện sẽ chạy các tác vụ khác, gọi lại hoặc thực hiện các thao tác IO. Nhiệm vụ cũng có thể bị hủy bỏ
  • Một vòng lặp Sự kiện được liên kết với một Chủ đề
  • SelectorEventLoop — Vòng lặp sự kiện dựa trên mô-đun bộ chọn (epoll()/kqueue()/select()) để ghép kênh I/O hiệu quả và cao cấp
  • ProactorEventLoop — Vòng lặp sự kiện cho windows
import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
0

tương lai

def read_file(file_name):
for row in open(file_name, "r"):
yield row


def read_csv_row(file_name):
for row in read_file(file_name):
yield row.split(',')


def read_csv(file_name):
for items in read_csv_row(file_name):
print("Row: " + str(items))


read_csv('test.csv')
# Output:
Row: ['col1', 'col2', 'col3\n']
Row: ['1', '2', '3\n']
Row: ['3', '4', '5']
7 là một đối tượng có thể chờ ở mức độ thấp đặc biệt đại diện cho kết quả cuối cùng của hoạt động không đồng bộ. Đối tượng tương lai được chờ đợi, điều đó có nghĩa là coroutine sẽ đợi cho đến khi Tương lai được giải quyết ở một số nơi khác

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
1

Phối hợp giữa các hợp đồng tương lai

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
2

nhiệm vụ

Nhiệm vụ là một lớp con của Tương lai. Các tác vụ được sử dụng để lên lịch cho các coroutine đồng thời trong vòng lặp sự kiện. Coroutine được bao bọc trong một Tác vụ với các chức năng như

def read_file(file_name):
for row in open(file_name, "r"):
yield row


def read_csv_row(file_name):
for row in read_file(file_name):
yield row.split(',')


def read_csv(file_name):
for items in read_csv_row(file_name):
print("Row: " + str(items))


read_csv('test.csv')
# Output:
Row: ['col1', 'col2', 'col3\n']
Row: ['1', '2', '3\n']
Row: ['3', '4', '5']
8, coroutine sẽ tự động được lên lịch để chạy sớm. Tác vụ có add_done_callback() để xử lý thêm việc dọn dẹp mã/xử lý logic

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
3

@loại. công việc thường ngày

Trình trang trí để gắn cờ trình tạo là một coroutine. Rất giống với asyncio. coroutine() và ít được chú ý hơn. Nó cho phép khả năng tương tác giữa các coroutine dựa trên trình tạo hiện có trong asyncio và các coroutine gốc (không đồng bộ)

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
4

Máy phát điện không đồng bộ

'yield' bên trong một coroutine gốc trả về một trình tạo không đồng bộ

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
5

Trình tạo có async/await được hỗ trợ với giao thức lặp không đồng bộ mới

Giao thức lặp không đồng bộ

  1. Phương thức __aiter__ trả về trình vòng lặp không đồng bộ
  2. Một phương thức __anext__ trả về một đối tượng có thể chờ đợi, sử dụng ngoại lệ StopIteration cho các giá trị “yield” và ngoại lệ StopAsyncIteration để báo hiệu kết thúc quá trình lặp
import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
6

không đồng bộ cho

Đơn giản hóa việc lặp lại trình tạo không đồng bộ (năng suất)

import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
73. Tóm lược
  • Từ khóa 'yield' tạo trình tạo thông thường. 'yield from' là một phím tắt để lặp lại và làm cạn kiệt trình tạo
  • máy phát điện. send() giúp gửi các giá trị đến một coroutine. '(yield)' là hai hướng để lặp lại giữa các coroutine
  • Vòng lặp sự kiện sử dụng lập lịch hợp tác. Các tác vụ đồng thời được lên lịch trong Vòng lặp sự kiện được quản lý bởi Chủ đề
  • @asyncio. coroutine tạo các đối tượng coroutine trình tạo asyncio và sử dụng 'yield from' để hoạt động trên các coroutine gốc/trình tạo. Câu lệnh
    def magic_pot(start=1, end=1000):
    while True:
    yield random.randint(start, end)
    gen = magic_pot()
    for a in gen:
    print(a)
    # Output: prints numbers without stopping
    569
    ...
    5 từ bỏ quyền điều khiển trở lại vòng lặp sự kiện để cho các coroutine khác thực thi
  • @loại. coroutine tương tự như @asyncio. coroutine giúp chuyển đổi các trình tạo thông thường thành các đối tượng coroutine và có thể tương tác giữa các coroutine bản địa
  • asyncio là một thư viện để viết mã đồng thời bằng cú pháp async/await
  • các coroutines được khai báo với cú pháp async/await là cách ưa thích để viết các ứng dụng asyncio
  • async/await tương đương mới nhất với @asyncio. coroutine/'sản lượng từ'
  • quy trình gốc/trình tạo, tương lai, các nhiệm vụ được chờ đợi
  • Tương lai là một đối tượng có thể chờ ở mức độ thấp đặc biệt đại diện cho kết quả cuối cùng của hoạt động không đồng bộ
  • Nhiệm vụ là một lớp con của Tương lai. Các tác vụ được sử dụng để lên lịch cho các coroutine đồng thời trong vòng lặp sự kiện để thực thi
  • 'async for' được sử dụng để lặp qua trình tạo không đồng bộ
  • 'async with' được sử dụng để thực hiện các thao tác không đồng bộ với dọn dẹp (thu gom rác)
4. Ví dụ về trình thu thập API HTTP đơn giản
import randomdef simple_generator():
yield 10
yield 100


gen = simple_generator()
print(gen)
print(next(gen))
print(gen.__next__())
try:
print(next(gen))
except StopIteration:
print('iteration stopped')
# Output:
<generator object simple_generator at 0x100fa48b8>
10
100
iteration stopped
8

Người giới thiệu

Đặc biệt Cảm ơn tất cả những người đã giúp tôi hiểu các khái niệm phức tạp với blog/bài thuyết trình chi tiết của họ. Tôi đã sử dụng một phần định nghĩa/ví dụ tham khảo từ một số liên kết tham khảo

  • www. dabeaz. com trình bày xuất sắc và mã nguồn
  • Abu Ashraf Masnun đã viết những bài báo xuất sắc về những chủ đề này. Kiểm tra blog của anh ấy (http. // masnun. com)
  • https. //trăn thật. com/async-io-python/#other-features-async-for-and-async-generators-comprehensions
  • https. //www. giáo dục. io/blog/python-concurrency-make-sense-of-asyncio
  • https. // cáu kỉnh. ca/how-the-heck-does-async-await-work-in-python-3-5/

Vui lòng cho tôi biết phản hồi/chỉnh sửa của bạn về định nghĩa/mã. Nếu bạn đang đọc dòng cuối cùng này, bạn đã có rất nhiều kiên nhẫn/quan tâm để đọc một bài viết dài như vậy và cảm ơn vì điều đó. )

Làm cách nào để trả về giá trị từ Python coroutine?

Trả về giá trị từ Coroutines . Trong trường hợp này, run_until_complete() cũng trả về kết quả của coroutine mà nó đang chờ.

Năng suất trong coroutine là gì?

2. Khái niệm cơ bản. Điều đầu tiên cần biết về hàm yield() là nó là hàm tạm dừng được sử dụng trong ngữ cảnh của Kotlin Coroutines . Khi năng suất () được gọi, nó sẽ tạo ra luồng (hoặc nhóm luồng) của trình điều phối coroutine hiện tại cho các coroutine khác để chạy nếu có thể.

Chúng tôi có thể mang lại danh sách bằng Python không?

Từ khóa suất, không giống như câu lệnh trả về, được sử dụng để biến một hàm Python thông thường thành trình tạo . Điều này được sử dụng thay thế cho việc trả lại toàn bộ danh sách cùng một lúc.

Sự khác biệt giữa máy phát điện và coroutine là gì?

Trình tạo cho phép bạn tạo các hàm trông giống như trình vòng lặp đối với người tiêu dùng. Coroutine là một phần mở rộng của khái niệm chức năng truyền thống . Một hàm sẽ trao lại quyền điều khiển cho người gọi của nó một lần thông qua câu lệnh return. Một coroutine sẽ trả lại quyền kiểm soát nhiều lần bằng cách gọi năng suất.