2015-01-06 17 views
32

Tôi có đoạn mã sau:Khi sử dụng asyncio, làm thế nào để bạn cho phép tất cả các nhiệm vụ chạy để kết thúc trước khi tắt vòng lặp sự kiện

@asyncio.coroutine 
def do_something_periodically(): 
    while True: 
     asyncio.async(my_expensive_operation()) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

tôi chạy chức năng này cho đến khi hoàn tất. Vấn đề xảy ra khi tắt máy được cài đặt - chức năng hoàn thành và mọi tác vụ đang chờ xử lý sẽ không bao giờ chạy. (Bạn thấy đây là lỗi

task: <Task pending coro=<report() running at script.py:33> wait_for=<Future pending cb=[Task._wakeup()]>> 

). Làm cách nào để lên lịch tắt máy một cách chính xác?

Để đưa ra một số ngữ cảnh, tôi viết một màn hình hệ thống đọc từ/proc/stat sau mỗi 5 giây, tính toán mức sử dụng CPU trong khoảng thời gian đó, và sau đó gửi kết quả đến máy chủ. Tôi muốn tiếp tục lập kế hoạch cho các công việc giám sát này cho đến khi tôi nhận được sigterm, khi tôi ngừng lập kế hoạch, hãy đợi tất cả các công việc hiện tại để hoàn thành và thoát ra một cách duyên dáng.

+0

để cung cấp cho một số bối cảnh, tôi đang viết một màn hình hệ thống mà đọc từ/proc/stat mỗi 5 giây , tính toán mức sử dụng CPU trong khoảng thời gian đó và sau đó gửi kết quả đến rver. Tôi muốn tiếp tục lập kế hoạch cho các công việc giám sát này cho đến khi tôi nhận được sigterm, khi tôi ngừng lập kế hoạch, hãy đợi tất cả các công việc hiện tại để hoàn thành và thoát ra một cách duyên dáng. – derekdreery

+0

bạn đã thử 'sản lượng từ my_expensive_operation() \ n thu được từ asyncio.sleep (my_interval - timer()% my_interval)' thay thế? – jfs

+0

Tôi chỉ có thể ngủ đủ lâu để tôi biết mọi thứ đã hoàn thành, nhưng điều này không có vẻ rất sạch sẽ. Tôi đã tự hỏi nếu có một cách để lịch trình công việc và sau đó chạy vòng lặp cho đến khi tất cả các nhiệm vụ theo lịch trình được hoàn thành. Trong javascript (node.js), nếu chương trình chính đạt đến kết thúc nhưng có các cuộc gọi lại được thiết lập, thì quá trình này sẽ chạy cho đến khi tất cả các cuộc gọi lại bị xóa. – derekdreery

Trả lời

33

Bạn có thể lấy các nhiệm vụ chưa hoàn thành và chạy vòng lặp lại cho đến khi họ hoàn tất, sau đó đóng vòng lặp hoặc thoát khỏi chương trình của bạn.

pending = asyncio.Task.all_tasks() 
loop.run_until_complete(asyncio.gather(*pending)) 
  • đang chờ xử lý là danh sách các tác vụ đang chờ xử lý.
  • asyncio.gather() cho phép đợi nhiều tác vụ cùng một lúc.

Nếu bạn muốn đảm bảo tất cả các nhiệm vụ được hoàn thành bên trong một coroutine (có thể bạn có một "chính" coroutine), bạn có thể làm theo cách này, ví dụ:

@asyncio.coroutine 
def do_something_periodically(): 
    while True: 
     asyncio.async(my_expensive_operation()) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

    yield from asyncio.gather(*asyncio.Task.all_tasks()) 

Ngoài ra, trong trường hợp này, vì tất cả các nhiệm vụ được tạo ra trong coroutine cùng, bạn đã có quyền truy cập vào các nhiệm vụ:

@asyncio.coroutine 
def do_something_periodically(): 
    tasks = [] 
    while True: 
     tasks.append(asyncio.async(my_expensive_operation())) 
     yield from asyncio.sleep(my_interval) 
     if shutdown_flag_is_set: 
      print("Shutting down") 
      break 

    yield from asyncio.gather(*tasks) 
+1

Rất hữu ích! Chỉ cần lưu ý về phương pháp thứ hai: tôi nghĩ * rằng mỗi tác vụ bạn thêm vào danh sách đại diện cho một bộ mô tả tập tin mở - điều này có nghĩa là trên (nói) Linux, bạn có thể nhấn giới hạn tập tin mở của bạn ('ulimit -n') trước coroutine kết thúc. – detly

+0

Xin chào, Bạn có ý gì khi "đại diện"? AFAIK, các tác vụ không mở đối tượng tệp. –

+0

Tôi đã tìm thấy, sử dụng phương pháp thứ hai, rằng tôi nhận được thông báo lỗi về việc có quá nhiều bộ mô tả tệp mở. Tôi * nghĩ * rằng mỗi tác vụ yêu cầu một bộ mô tả tập tin để làm việc. Lưu ý rằng một "bộ mô tả tập tin" không giống như một tập tin mở, chúng cũng có thể được sử dụng bởi ['select()'] (http://www.gnu.org/software/libc/manual/ html_node/Waiting-for-I_002fO.Cuộc gọi html # index-file-descriptor-sets_002c-for-select (mà tôi tin rằng thư viện 'asyncio' sử dụng). Vì vậy, nếu bạn có giới hạn người dùng của một vài nghìn mô tả tệp mở và nhiều tác vụ hơn thế, bạn có thể gặp phải sự cố. – detly

Các vấn đề liên quan