2014-05-21 27 views
6

xử lý mô hình Bài viết của tôi bằng cách sử dụng tín hiệu post_save:tín hiệu không đồng bộ với asyncio

from django.core.signals import request_finished 
from django.dispatch import receiver 
from models import MyModel 
from pipeline import this_takes_forever 


@receiver(post_save, sender=MyModel) 
def my_callback(sender, **kwargs): 
    this_takes_forever(sender) 

Các this_takes_forever thói quen làm IO vì vậy tôi muốn hoãn nó để tránh chặn các yêu cầu quá nhiều.

Tôi nghĩ đây là trường hợp sử dụng tuyệt vời cho mô-đun asyncio mới. Nhưng tôi có một thời gian khó khăn để có được tâm trí của tôi xung quanh toàn bộ quá trình.

Tôi nghĩ rằng tôi sẽ có thể thích ứng với người nhận tín hiệu như thế này:

@receiver(post_save, sender=MyModel) 
def my_callback(sender, **kwargs): 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(this_takes_forever(sender)) 
    loop.close() 

Cung cấp this_takes_forever cũng được điều chỉnh để có một coroutine.

@coroutine 
def this_takes_forever(instance): 
    # do something with instance 
    return instance 

Điều này nghe có vẻ quá huyền diệu. Và trên thực tế, nó dừng lại với một số AssertionError:

AssertionError at /new/ 
There is no current event loop in thread 'Thread-1'. 

Tôi không thấy nơi nào tôi nên bắt đầu vòng lặp trong ngữ cảnh này. Bất cứ ai đã thử một cái gì đó như thế này?

Trả lời

3

Bạn không nhận được bất kỳ lợi ích trong trường hợp của bạn:

@receiver(post_save, sender=MyModel) 
def my_callback(sender, **kwargs): 
    this_takes_forever(sender) 

bằng

@receiver(post_save, sender=MyModel) 
def my_callback(sender, **kwargs): 
    loop = asyncio.get_event_loop() 
    loop.run_until_complete(this_takes_forever(sender)) 
    loop.close() 

về thời gian thực hiện. loop.run_until_complete chờ kết thúc của this_takes_forever(sender) cuộc gọi coroutine, vì vậy bạn nhận được cuộc gọi đồng bộ trong trường hợp thứ hai cũng như trong trường hợp cũ.

Giới thiệu AssertionError: bạn khởi động ứng dụng Django ở chế độ đa luồng, nhưng asyncio làm vòng lặp sự kiện mặc định cho chỉ chuỗi chính - bạn nên đăng ký vòng lặp mới cho mỗi chuỗi do người dùng tạo nơi bạn cần gọi mã asyncio.

Nhưng, nói lại, asyncio không thể giải quyết vấn đề cụ thể của bạn, nó chỉ không tương thích với Django.

Cách tiêu chuẩn cho Django là để trì hoãn mã dài chạy vào nhiệm vụ cần tây (xem http://www.celeryproject.org/)

+0

Ok với điểm đầu tiên. Có lẽ đây chỉ là một ví dụ xấu, tôi sẽ cố gắng tái cấu trúc để rõ ràng hơn. Dù sao tôi không sử dụng django trong bất kỳ chế độ đa luồng nào, chỉ cần chạy 'runserver' mặc định là một chuỗi. Nhìn sâu hơn có vẻ như tôi cần phải dây một số máy chủ không chặn như [aiohttp] (https://github.com/KeepSafe/aiohttp) – tutuca

+1

Từ sự hiểu biết của tôi 'runserver' thực sự tạo ra chủ đề mới để chạy ứng dụng Django bên trong nó bằng cách mặc định - đó là cách tính năng 'autoreload' hoạt động. –

+1

về aiohttp - xin lưu ý rằng thư viện ở mức quá thấp so với Django hoặc, ví dụ: tornado.web. Tôi đang làm việc trên giao diện người dùng thân thiện hơn nhưng công việc đang ở giai đoạn rất sớm. –

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