मैं एक फ्लास्क ऐप पर काम कर रहा हूं जिसमें क्लाइंट की प्रतिक्रिया उन उत्तरों पर निर्भर करती है जो मुझे कुछ बाहरी एपीआई से मिलते हैं। इन एपीआई के अनुरोध एक दूसरे से तार्किक रूप से स्वतंत्र हैं, इसलिए इन अनुरोधों को समानांतर में भेजकर गति लाभ प्राप्त किया जा सकता है (नीचे दिए गए उदाहरण में प्रतिक्रिया समय लगभग आधा हो जाएगा)।

यह मुझे लगता है कि इसे प्राप्त करने का सबसे सरल और सबसे आधुनिक तरीका है asyncio का उपयोग करना और सभी कार्यों को एक अलग async फ़ंक्शन में संसाधित करना जिसे asyncio.run() का उपयोग करके फ्लास्क व्यू फ़ंक्शन से कहा जाता है। मैंने नीचे एक छोटा कामकाजी उदाहरण शामिल किया है।

एक अलग कार्यकर्ता प्रक्रिया के साथ अजवाइन या किसी अन्य प्रकार की कतार का उपयोग करना वास्तव में यहां समझ में नहीं आता है, क्योंकि प्रतिक्रिया को उत्तर भेजने से पहले वैसे भी एपीआई परिणामों की प्रतीक्षा करनी पड़ती है। जहाँ तक मैं देख सकता हूँ यह एक प्रकार है इस विचार का जहां एक प्रोसेसिंग लूप को asyncio के माध्यम से एक्सेस किया जाता है। इसके लिए निश्चित रूप से आवेदन हैं, लेकिन मुझे लगता है कि अगर हम वास्तव में किसी अनुरोध का उत्तर देने से पहले आईओ को समानांतर करना चाहते हैं तो यह अनावश्यक रूप से जटिल है।

हालांकि, मुझे पता है कि फ्लास्क के भीतर से विभिन्न प्रकार के मल्टीथ्रेडिंग का उपयोग करने में कुछ नुकसान हो सकते हैं। इसलिए मेरे प्रश्न हैं:

  1. क्या उत्पादन वातावरण में उपयोग किए जाने पर नीचे दिए गए इम्प्लांटेशन को सुरक्षित माना जाएगा? यह उस तरह के सर्वर पर निर्भर करता है जिस पर हम फ्लास्क चलाते हैं? विशेष रूप से, बिल्ट-इन डेवलपमेंट सर्वर या एक विशिष्ट मल्टी-वर्कर गनिकोर्न सेटअप जैसे कि https://flask.palletsprojects.com/en/1.1.x/deploying/wsgi-standalone/#gunicorn?
  2. क्या फ्लास्क के ऐप के बारे में कोई विचार किया जाना है और एसिंक्स फ़ंक्शन में संदर्भों का अनुरोध करना है या क्या मैं बस उनका उपयोग कर सकता हूं जैसा कि मैं किसी अन्य फ़ंक्शन में करूंगा? अर्थात। क्या मैं अपने एप्लिकेशन कॉन्फिग तक पहुंचने या जी और सत्र ऑब्जेक्ट्स का उपयोग करने के लिए बस current_app आयात कर सकता हूं? उन्हें लिखते समय संभावित दौड़ स्थितियों पर स्पष्ट रूप से विचार करना होगा, लेकिन क्या कोई अन्य मुद्दे हैं? मेरे मूल परीक्षणों में (उदाहरण में नहीं) सब कुछ ठीक काम करता प्रतीत होता है।
  3. क्या कोई अन्य समाधान है जो इस पर सुधार करेगा?

यहाँ मेरा उदाहरण आवेदन है। चूंकि एस्किनियो इंटरफ़ेस समय के साथ थोड़ा बदल गया है, शायद यह ध्यान देने योग्य है कि मैंने इसे पायथन 3.7 और 3.8 पर परीक्षण किया है और मैंने एसिंकियो के बहिष्कृत हिस्सों से बचने के लिए अपनी पूरी कोशिश की है।

import asyncio
import random
import time
from flask import Flask

app = Flask(__name__)

async def contact_api_a():
    print(f'{time.perf_counter()}: Start request 1')
    # This sleep simulates querying and having to wait for an external API
    await asyncio.sleep(2)

    # Here is our simulated API reply
    result = random.random()

    print(f'{time.perf_counter()}: Finish request 1')

    return result


async def contact_api_b():
    print(f'{time.perf_counter()}: Start request 2')
    await asyncio.sleep(1)

    result = random.random()

    print(f'{time.perf_counter()}: Finish request 2')

    return result


async def contact_apis():
    # Create the two tasks
    task_a = asyncio.create_task(contact_api_a())
    task_b = asyncio.create_task(contact_api_b())

    # Wait for both API requests to finish
    result_a, result_b = await asyncio.gather(task_a, task_b)

    print(f'{time.perf_counter()}: Finish both requests')

    return result_a, result_b


@app.route('/')
def hello_world():
    start_time = time.perf_counter()

    # All async processes are organized in a separate function
    result_a, result_b = asyncio.run(contact_apis())

    # We implement some final business logic before finishing the request
    final_result = result_a + result_b

    processing_time = time.perf_counter() - start_time

    return f'Result: {final_result:.2f}; Processing time: {processing_time:.2f}'
0
m_o_h 7 सितंबर 2020, 16:20

1 उत्तर

सबसे बढ़िया उत्तर
  1. यह उत्पादन में चलाने के लिए सुरक्षित होगा लेकिन asyncio Gunicorn async श्रमिकों, जैसे gevent या eventlet के साथ कुशलता से काम नहीं करेगा। ऐसा इसलिए है क्योंकि result_a, result_b = asyncio.run(contact_apis()) gevent/eventlet इवेंट-लूप को तब तक ब्लॉक कर देगा जब तक कि यह पूरा नहीं हो जाता, जबकि gevent/eventlet स्पॉन समकक्षों का उपयोग नहीं करेगा। फ्लास्क सर्वर का उत्पादन में उपयोग नहीं किया जाना चाहिए। Gunicorn थ्रेडेड वर्कर (या कई Gunicorn प्रोसेस) ठीक रहेगा, क्योंकि asyncio थ्रेड/प्रोसेस को ब्लॉक कर देगा।

  2. ग्लोबल्स ठीक काम करेंगे क्योंकि वे या तो थ्रेड (थ्रेडेड वर्कर्स) या ग्रीन-थ्रेड (gevent/eventlet) से बंधे होते हैं, न कि asyncio टास्क से।

  3. मैं कहूंगा कि Quart एक सुधार है (मैं क्वार्ट लेखक हूं)। क्वार्ट फ्लास्क एपीआई है जिसे asyncio का उपयोग करके फिर से लागू किया गया है। क्वार्ट के साथ उपरोक्त स्निपेट है,

import asyncio
import random
import time
from quart import Quart
    
app = Quart(__name__)
    
async def contact_api_a():
    print(f'{time.perf_counter()}: Start request 1')
    # This sleep simulates querying and having to wait for an external API
    await asyncio.sleep(2)

    # Here is our simulated API reply
    result = random.random()

    print(f'{time.perf_counter()}: Finish request 1')

    return result
    
async def contact_api_b():
    print(f'{time.perf_counter()}: Start request 2')
    await asyncio.sleep(1)

    result = random.random()

    print(f'{time.perf_counter()}: Finish request 2')

    return result
    

async def contact_apis():
    # Create the two tasks
    task_a = asyncio.create_task(contact_api_a())
    task_b = asyncio.create_task(contact_api_b())

    # Wait for both API requests to finish
    result_a, result_b = await asyncio.gather(task_a, task_b)

    print(f'{time.perf_counter()}: Finish both requests')

    return result_a, result_b
    
@app.route('/')
async def hello_world():
    start_time = time.perf_counter()

    # All async processes are organized in a separate function
    result_a, result_b = await contact_apis()

    # We implement some final business logic before finishing the request
    final_result = result_a + result_b

    processing_time = time.perf_counter() - start_time

    return f'Result: {final_result:.2f}; Processing time: {processing_time:.2f}'

मैं एक asyncio आधारित अनुरोध पुस्तकालय का उपयोग करने का भी सुझाव दूंगा जैसे कि httpx

0
pgjones 7 सितंबर 2020, 14:18