Python chạy nhiều chức năng không đồng bộ

Một trong những tính năng đẹp hơn là một phần của Python 3 là chức năng ________ 61 / ________ 62 mới. Đây hiện là một tính năng của trình thông dịch Python và phần lớn có thể thay thế các gói cũ hơn như Twisted hoặc Eventlet. Một số người có thể thích phong cách lập trình của các framework như Twisted, nhưng tôi thì không. Mô-đun

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
3 cung cấp cho bạn tất cả các công cụ cần thiết để chạy đồng thời một loạt tác vụ mà không thực sự cần phải lo lắng quá nhiều về cách bất kỳ tác vụ nào trong số này được triển khai. Thay đổi lớn nhất là nhu cầu sử dụng từ khóa
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
1 và
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
2 trong mã Python của bạn. Miễn là các nhiệm vụ của bạn bằng cách nào đó bị ràng buộc bởi IO [như máy chủ trò chuyện], mọi thứ sẽ hoạt động khá tốt. Tất cả thực thi thực tế vẫn diễn ra trên một luồng hệ điều hành duy nhất. Python thực tế là đơn luồng do GIL và không chắc điều này sẽ thay đổi trong tương lai gần

Nếu bạn đang tìm kiếm phần giới thiệu cơ bản về cách sử dụng ________ 62 / ________ 61, tôi sẽ bắt đầu với hướng dẫn này

Golang's
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
4

Việc bổ sung ________ 61/________ 62 trong Python thực sự khiến nó ngang bằng với các ngôn ngữ khác khi bạn đang cố gắng thực hiện một loạt công cụ kiểu mạng. Hiện tôi đã xây dựng một số dự án thử nghiệm, chẳng hạn như một máy chủ có thể truyền nguồn cấp dữ liệu sự kiện tới trình duyệt bằng WebSockets. Điều này đã được thực hiện bằng cách sử dụng gói websockets. Đó là một dự án đơn giản và tôi không gặp bất kỳ khó khăn nào trong quá trình học tập. Quay lại khi Golang vừa mới đạt phiên bản 1. 0 Tôi thường xuyên sử dụng Go tại nơi làm việc. Một trong những tính năng thú vị của cờ vây là câu lệnh

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
4. Câu lệnh
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
4 cho phép bạn đợi nhiều câu lệnh cho đến khi một trong số chúng có sẵn kết quả

Đây là một ví dụ, được sử dụng theo giấy phép của Mark McGranaghan từ đây

package main

import [
    "fmt"
    "time"
]

func main[] {

    c1 := make[chan string]
    c2 := make[chan string]

    go func[] {
        time.Sleep[1 * time.Second]
        c1 = 100 # run until we get some results
8 trong bộ nhớ. Khi sự kiện nguồn sự kiện thứ hai phát ra sự kiện kích hoạt, bạn xử lý
q1 = asyncio.Queue[] # pretend something puts stuff in this
q1 = asyncio.Queue[] # pretend something puts stuff in this
done = False
results = []
while not done:
  # This really doesn't work, don't try it 
  done, pending = await asyncio.wait[[q1.get[], q2.get[]], return_when = asyncio.FIRST_COMPLETED]

  for d in done:
    results.append[d.result[]]
  done = len[results] >= 100 # run until we get some results
8 và cập nhật tất cả các hàng thích hợp

Lớp tương đương với các kênh của Golang trong Python là

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
40. Đó là một hàng đợi sự kiện được tùy chọn giới hạn số lượng sự kiện mà nó nắm giữ. Khi đặt đồ vật vào hàng đợi, bạn chỉ cần
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
41 để chặn cho đến khi đồ vật được đặt vào hàng đợi. Nếu không gian đã có sẵn, điều này sẽ trả lại ngay lập tức. Để lấy các mục từ hàng đợi, bạn chỉ cần thực hiện
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
42. Cuộc gọi này chặn cho đến khi một mục có thể được lấy từ hàng đợi

Kích hoạt mỗi phút một lần nghe có vẻ phức tạp, nhưng không phải vậy. Để có được một nguồn sự kiện với một sự kiện kích hoạt, cứ sau 60 giây, bạn thực sự chỉ cần bọc hàm

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
43 dựng sẵn

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'

Nếu bạn gọi

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
44, kết quả sẽ không có trong ít nhất 60 giây

Trường hợp Python xuất hiện ngắn là nếu bạn muốn đợi nhiều hàng đợi cùng một lúc. Không có tương đương trực tiếp với câu lệnh

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
4 từ Golang. Những thứ có sẵn gần nhất trong Python là
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
46 và
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
47. Tài liệu cho các chức năng đó có sẵn tại đây

Sử dụng

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
46 sẽ trả lại cho bạn kết quả của các coroutine mà bạn thường sẽ
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
2 từng cái một, theo bất kỳ thứ tự nào mà chúng phải hoàn thành. Rõ ràng, không có sự kiểm soát nào đối với thứ tự của kết quả. Vì vậy, điều này không thực sự hữu ích

Hàm

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
47 theo mặc định chờ tất cả các phần chờ hoàn thành. Vì vậy, bạn không nhận được kết quả khi chúng có sẵn. Bạn có thể thay đổi điều này bằng cách chuyển tham số của
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
51 được đặt thành
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
52 để nhận kết quả đầu tiên ngay khi có sẵn

Cả hai chức năng này đều không thể so sánh trực tiếp với việc sử dụng câu lệnh Golang

async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
4 bên trong vòng lặp
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
54. Câu lệnh
async def after_one_minute[]:
  await asyncio.sleep[60.0]
  return 'trigger'
4 cho phép bạn tiếp tục lấy đi nhận lại các mục từ một kênh miễn là kênh đó vẫn còn các mục trong đó. Cố gắng thực hiện điều này trong mã Python kết thúc với một cái gì đó như thế này

q1 = asyncio.Queue[] # pretend something puts stuff in this
q1 = asyncio.Queue[] # pretend something puts stuff in this
done = False
results = []
while not done:
  # This really doesn't work, don't try it 
  done, pending = await asyncio.wait[[q1.get[], q2.get[]], return_when = asyncio.FIRST_COMPLETED]

  for d in done:
    results.append[d.result[]]
  done = len[results] >= 100 # run until we get some results

Hóa ra đoạn mã trên có vô số vấn đề

  1. Các giá trị
    async def after_one_minute[]:
      await asyncio.sleep[60.0]
      return 'trigger'
    
    56 và
    async def after_one_minute[]:
      await asyncio.sleep[60.0]
      return 'trigger'
    
    57 là loại
    async def after_one_minute[]:
      await asyncio.sleep[60.0]
      return 'trigger'
    
    58 và việc tìm ra kết quả đến từ đâu là điều không hề đơn giản
  2. async def after_one_minute[]:
      await asyncio.sleep[60.0]
      return 'trigger'
    
    56 và
    async def after_one_minute[]:
      await asyncio.sleep[60.0]
      return 'trigger'
    
    57 chứa các đối tượng thuộc loại
    package main
    
    import [
        "fmt"
        "time"
    ]
    
    func main[] {
    
        c1 := make[chan string]
        c2 := make[chan string]
    
        go func[] {
            time.Sleep[1 * time.Second]
            c1 

Chủ Đề