2017-12-16 98 views
5

Tôi muốn thực hiện chức năng async mỗi khi tuyến đường bình được thực hiện. Hiện tại chức năng abar của tôi chưa bao giờ được thực hiện. Bạn có thể cho tôi biết tại sao? Cảm ơn bạn rất nhiều:Python3 Gọi Asyncio từ tuyến Flask

import asyncio 
from flask import Flask 

async def abar(a): 
    print(a) 

loop = asyncio.get_event_loop() 
app = Flask(__name__) 

@app.route("/") 
def notify(): 
    asyncio.ensure_future(abar("abar"), loop=loop) 
    return "OK" 

if __name__ == "__main__": 
    app.run(debug=False, use_reloader=False) 
    loop.run_forever() 

Tôi đã cố gắng đặt một cuộc gọi chặn trong một chuỗi riêng biệt. Nhưng nó vẫn không gọi hàm abar.

import asyncio 
from threading import Thread 
from flask import Flask 

async def abar(a): 
    print(a) 

app = Flask(__name__) 

def start_worker(loop): 
    asyncio.set_event_loop(loop) 
    try: 
     loop.run_forever() 
    finally: 
     loop.close() 

worker_loop = asyncio.new_event_loop() 
worker = Thread(target=start_worker, args=(worker_loop,)) 

@app.route("/") 
def notify(): 
    asyncio.ensure_future(abar("abar"), loop=worker_loop) 
    return "OK" 

if __name__ == "__main__": 
    worker.start() 
    app.run(debug=False, use_reloader=False) 
+2

'app.run' và' loop.run_forever' đều bị chặn. Có lẽ bạn nên sử dụng một chuỗi. Nếu bạn _need_ sử dụng asyncio, bạn nên xem xét một trong các khung công tác giống như Flask được xây dựng trên đầu trang của nó. – dirn

+0

@dim Cảm ơn bạn rất nhiều. Tôi đã cố gắng di chuyển một ngăn chặn thành một sợi riêng biệt. S. câu hỏi đã chỉnh sửa của tôi! – user24502

Trả lời

3

Đối với cùng một lý do bạn sẽ không thấy in này:

if __name__ == "__main__": 
    app.run(debug=False, use_reloader=False) 
    print('Hey!') 
    loop.run_forever() 

loop.run_forever() không bao giờ được gọi là kể từ khi @dirn đã lưu ý app.run cũng được ngăn chặn.

Chạy vòng lặp sự kiện chặn toàn cầu - chỉ là cách bạn có thể chạy asyncio coroutines và nhiệm vụ, nhưng không tương thích với việc chạy chặn ứng dụng Flask (hoặc với bất kỳ thứ gì khác nói chung).

Nếu bạn muốn sử dụng khung web không đồng bộ, bạn nên chọn một khung được tạo không đồng bộ. Ví dụ, có lẽ phổ biến nhất hiện nay là aiohttp:

from aiohttp import web 


async def hello(request): 
    return web.Response(text="Hello, world") 


if __name__ == "__main__": 
    app = web.Application() 
    app.router.add_get('/', hello) 
    web.run_app(app) # this runs asyncio event loop inside 

UPD:

Về thử của bạn để chạy vòng lặp sự kiện trong chủ đề nền. Tôi đã không điều tra nhiều, nhưng có vẻ như vấn đề liên quan đến sự an toàn của tread: nhiều đối tượng asyncio không an toàn. Nếu bạn thay đổi mã theo cách này, mã sẽ hoạt động:

def _create_task(): 
    asyncio.ensure_future(abar("abar"), loop=worker_loop) 

@app.route("/") 
def notify(): 
    worker_loop.call_soon_threadsafe(_create_task) 
    return "OK" 

Nhưng một lần nữa, ý tưởng này rất tồi. Nó không chỉ là rất bất tiện, nhưng tôi đoán sẽ không có ý nghĩa nhiều: nếu bạn đang đi để sử dụng thread để bắt đầu asyncio, tại sao không just use threads in Flask thay vì asyncio? Bạn sẽ có Flask bạn muốn và song song.

Nếu tôi vẫn không thuyết phục được bạn, ít nhất hãy xem dự án Flask-aiohttp. Nó đã gần với api Flask và tôi nghĩ tốt hơn là những gì bạn đang cố gắng làm.

+0

Cảm ơn bạn rất nhiều vì đã giải thích. Điều đó có ý nghĩa. Cũng là một ví dụ nhỏ đẹp của nó aiohttp. Thật không may tôi bị ràng buộc vào bình/bình cầu cho một kỹ năng alexa. Tôi đã sửa đổi câu hỏi ban đầu của mình và chuyển một cuộc gọi chặn trong một chuỗi riêng biệt. Nhưng vẫn không có may mắn – user24502

+0

@ user24502 ​​Tôi đã cập nhật câu trả lời. –

2

Một giải pháp đơn giản cho vấn đề của bạn (theo quan điểm sai lệch của tôi) là chuyển sang Quart từ Flask. Nếu đoạn mã của bạn đơn giản hóa,

import asyncio 
from quart import Quart 

async def abar(a): 
    print(a) 

app = Quart(__name__) 

@app.route("/") 
async def notify(): 
    await abar("abar") 
    return "OK" 

if __name__ == "__main__": 
    app.run(debug=False) 

Như đã lưu ý trong câu trả lời khác, ứng dụng Flask đang chặn và không tương tác với vòng lặp asyncio. Quart mặt khác là Flask API được xây dựng trên asyncio, vì vậy nó sẽ hoạt động như thế nào bạn mong đợi.

Cũng như bản cập nhật, Flask-Aiohttp không còn là maintained.

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