पायथन अनुरोधों के साथ अतुल्यकालिक अनुरोध


142

मैंने अनुरोध पुस्तकालय के दस्तावेज के भीतर दिए गए नमूने की कोशिश की अजगर के लिए ।

इसके साथ async.map(rs), मुझे प्रतिक्रिया कोड मिलते हैं, लेकिन मैं अनुरोध किए गए प्रत्येक पृष्ठ की सामग्री प्राप्त करना चाहता हूं। यह, उदाहरण के लिए, काम नहीं करता है:

out = async.map(rs)
print out[0].content

हो सकता है कि आपको जो प्रतिक्रियाएँ मिल रही हैं, वे खाली हों?
मेरिज जमरो

मेरे लिये कार्य करता है। कृपया पूर्ण त्रुटि पोस्ट कर रहे हैं।
चेवी

कोई त्रुटि नहीं है। यह हमेशा प्रदान किए गए परीक्षण यूआरएल द्वारा हमेशा के लिए चलता है।
21

यह स्पष्ट रूप से प्रकट होता है जब मैं यूआरएल पर यूआरएल का उपयोग करता हूं। http ठीक काम कर रहा है
trbck

लगता requests-threadsहै अब मौजूद है।
ऑरेंजडॉग

जवाबों:


154

ध्यान दें

निम्न उत्तर अनुरोधों पर लागू नहीं है v0.13.0 +। इस प्रश्न के लिखे जाने के बाद अतुल्यकालिक कार्यक्षमता को grequests में ले जाया गया। हालांकि, अगर आप बस बदल सकते requestsके साथ grequestsनीचे और यह काम करना चाहिए।

मैंने यह उत्तर छोड़ दिया है जैसा कि मूल प्रश्न को प्रतिबिंबित करने के लिए है जो अनुरोधों का उपयोग करने के बारे में था <v0.13.0।


async.map असिंक्रोनस के साथ कई कार्य करने के लिए आपको निम्न करना होगा:

  1. प्रत्येक वस्तु (आपके कार्य) के साथ आप क्या करना चाहते हैं उसके लिए एक फ़ंक्शन निर्धारित करें
  2. अपने अनुरोध में एक ईवेंट हुक के रूप में उस फ़ंक्शन को जोड़ें
  3. async.mapसभी अनुरोधों / कार्यों की सूची पर कॉल करें

उदाहरण:

from requests import async
# If using requests > v0.13.0, use
# from grequests import async

urls = [
    'http://python-requests.org',
    'http://httpbin.org',
    'http://python-guide.org',
    'http://kennethreitz.com'
]

# A simple task to do to each response object
def do_something(response):
    print response.url

# A list to hold our things to do via async
async_list = []

for u in urls:
    # The "hooks = {..." part is where you define what you want to do
    # 
    # Note the lack of parentheses following do_something, this is
    # because the response will be used as the first argument automatically
    action_item = async.get(u, hooks = {'response' : do_something})

    # Add the task to our list of things to do via async
    async_list.append(action_item)

# Do our list of things to do via async
async.map(async_list)

2
अपनी टिप्पणी छोड़ना अच्छा लगता है: नवीनतम अनुरोधों और grequests (अनुरोध 1.1.0 में max_retries विकल्प की कमी) के बीच संगतता के मुद्दों के कारण मुझे async को पुनः प्राप्त करने के लिए अनुरोधों को डाउनग्रेड करना पड़ा और मैंने पाया है कि अतुल्यकालिक कार्यक्षमता 0.13+ संस्करणों के साथ स्थानांतरित हो गई थी ( pypi.python.org/pypi/requests )
outforawhile

1
गूंगा प्रश्न: केवल अनुरोधों के विपरीत grequests का उपयोग करने की गति में वृद्धि क्या है? अनुरोधों के संबंध में क्या सीमाएँ हैं? जैसे 3500 अनुरोधों को async.map में रखना ठीक रहेगा?
ड्रॉप

10
from grequests import asyncकाम मत करो .. और मेरे लिए काम करने की यह परिभाषा def do_something(response, **kwargs):, मैं इसे stackoverflow.com/questions/15594015/…
एलन रुइन

3
यदि async.map कॉल अभी भी ब्लॉक है, तो यह एसिंक्रोनस कैसे है? अनुरोधों के अलावा खुद को अतुल्यकालिक रूप से भेजा जा रहा है, फिर भी पुनर्प्राप्ति समकालिक है?
bryanph

3
मेरे from requests import asyncद्वारा import grequests as asyncकाम करने की जगह ।
मार्टिन थोमा

80

async अब एक स्वतंत्र मॉड्यूल है: grequests

यहाँ देखें : https://github.com/kennethreitz/grequests

और वहाँ: पायथन पर कई HTTP अनुरोध भेजने के लिए आदर्श विधि?

स्थापना:

$ pip install grequests

उपयोग:

एक स्टैक का निर्माण करें:

import grequests

urls = [
    'http://www.heroku.com',
    'http://tablib.org',
    'http://httpbin.org',
    'http://python-requests.org',
    'http://kennethreitz.com'
]

rs = (grequests.get(u) for u in urls)

स्टैक भेजें

grequests.map(rs)

परिणाम जैसा दिखता है

[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]

grequests समवर्ती अनुरोधों के लिए एक सीमा निर्धारित नहीं करते हैं, अर्थात जब एक ही सर्वर पर कई अनुरोध भेजे जाते हैं।


11
समवर्ती अनुरोधों पर सीमा के संबंध में - आप नक्शा () / imap () चलाते समय एक पूल आकार निर्दिष्ट कर सकते हैं। 20 grequests.map (आरएस, आकार = 20) के लिए 20 समवर्ती कब्रें हैं।
सिंथेसाइजरपटेल

1
अब तक यह अजगर 3-सक्षम नहीं है (py3.4 पर v2.6 का निर्माण करने में विफल रहता है)।
सर्प

1
मैं async भाग को काफी नहीं समझता। यदि मैं results = grequests.map(rs)इस लाइन के ब्लॉक होने के बाद कोड देता हूं, तो मैं एसिंक्स प्रभाव देख सकता हूं?
एलन रुबिन

47

मैंने दोनों अनुरोधों-वायदा और grequests का परीक्षण किया । ग्रेक्वेस्ट तेज है लेकिन निर्भरता के साथ बंदर पैचिंग और अतिरिक्त समस्याएं लाता है। अनुरोध-वायदा grequests की तुलना में कई गुना धीमा है। मैं में अपने खुद के और बस लिपटे अनुरोध लिखने का फैसला किया ThreadPoolExecutor और यह लगभग रूप में तेजी से था grequests के रूप में, लेकिन बाहरी निर्भरता के बिना।

import requests
import concurrent.futures

def get_urls():
    return ["url1","url2"]

def load_url(url, timeout):
    return requests.get(url, timeout = timeout)

with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:

    future_to_url = {executor.submit(load_url, url, 10): url for url in     get_urls()}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            resp_err = resp_err + 1
        else:
            resp_ok = resp_ok + 1

यहां किस प्रकार का अपवाद संभव है?
धीमे हैरी

requests.exceptions.Timeout
Hodza

2
क्षमा करें, मुझे आपका प्रश्न समझ में नहीं आया। एकाधिक थ्रेड्स में केवल एकल url का उपयोग करें? केवल एक मामला DDoS पर हमला करता है))
होडाज़ा

1
मुझे समझ में नहीं आ रहा है कि इस उत्तर को इतने उभार क्यों मिले। OP प्रश्न async अनुरोधों के बारे में था। ThreadPoolExecutor थ्रेड चलाता है। हां, आप कई थ्रेड्स में अनुरोध कर सकते हैं, लेकिन यह कभी भी एक async प्रोग्राम नहीं होगा, इसलिए मैं मूल प्रश्न का उत्तर कैसे दे सकता हूं?
nagylzs 17

1
दरअसल, सवाल यह था कि समानांतर में URL कैसे लोड किए जाएं। और हाँ थ्रेड पूल निष्पादक सबसे अच्छा विकल्प नहीं है, यह async io का उपयोग करना बेहतर है, लेकिन यह पायथन में अच्छी तरह से काम करता है। और मुझे समझ में नहीं आ रहा है कि थ्रेड्स का उपयोग async के लिए क्यों नहीं किया जा सकता है? क्या होगा यदि आपको एसिंक्रोनस रूप से सीपीयू बाउंड कार्य चलाने की आवश्यकता है?
होडाज़ा

29

शायद अनुरोध-वायदा एक और विकल्प है।

from requests_futures.sessions import FuturesSession

session = FuturesSession()
# first request is started in background
future_one = session.get('http://httpbin.org/get')
# second requests is started immediately
future_two = session.get('http://httpbin.org/get?foo=bar')
# wait for the first request to complete, if it hasn't already
response_one = future_one.result()
print('response one status: {0}'.format(response_one.status_code))
print(response_one.content)
# wait for the second request to complete, if it hasn't already
response_two = future_two.result()
print('response two status: {0}'.format(response_two.status_code))
print(response_two.content)

यह कार्यालय दस्तावेज़ में भी अनुशंसित है । यदि आप जियोवेंट को शामिल नहीं करना चाहते हैं, तो यह एक अच्छा है।


1
सबसे आसान समाधानों में से एक। समवर्ती अनुरोधों की संख्या को मैक्स_वर्कर्स पैरामीटर को परिभाषित करके बढ़ाया जा सकता है
जोस चेरियन

1
इस स्केल के उदाहरण को देखना अच्छा होगा इसलिए हम लूप ओवर प्रति आइटम एक चर नाम का उपयोग नहीं कर रहे हैं।
user1717828

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

@CorneliuMaftuleac अच्छा बिंदु। थ्रेड उपयोग के संबंध में, आपको निश्चित रूप से इसकी देखभाल करने की आवश्यकता है और लाइब्रेरी थ्रेडिंग पूल या प्रोसेसिंग पूल को सक्षम करने के लिए एक विकल्प प्रदान करती है। ThreadPoolExecutor(max_workers=10)
ड्रीमपफ

@Dreampuf प्रसंस्करण पूल मुझे विश्वास है कि और भी बुरा है?
कोर्नेलियु मफ्तुलियाक

11

मेरे पास पोस्ट किए गए अधिकांश उत्तरों के साथ बहुत सारे मुद्दे हैं - वे या तो पदावनत पुस्तकालयों का उपयोग करते हैं जिन्हें सीमित विशेषताओं के साथ चित्रित किया गया है, या अनुरोध के निष्पादन पर बहुत अधिक जादू के साथ एक समाधान प्रदान करते हैं, जिससे त्रुटि संभालना मुश्किल हो जाता है। यदि वे उपरोक्त श्रेणियों में से एक में नहीं आते हैं, तो वे 3rd पार्टी लाइब्रेरी या पदावनत हैं।

कुछ समाधान http अनुरोधों में पूरी तरह से ठीक से काम करते हैं, लेकिन समाधान किसी अन्य प्रकार के अनुरोध के लिए कम हो जाते हैं, जो कि आकर्षक है। यहां अत्यधिक अनुकूलित समाधान आवश्यक नहीं है।

बस अंतर्निहित लाइब्रेरी asyncioका उपयोग किसी भी प्रकार के अतुल्यकालिक अनुरोधों को पूरा करने के लिए पर्याप्त है, साथ ही साथ जटिल और usecase विशिष्ट त्रुटि से निपटने के लिए पर्याप्त तरलता प्रदान करता है।

import asyncio

loop = asyncio.get_event_loop()

def do_thing(params):
    async def get_rpc_info_and_do_chores(id):
        # do things
        response = perform_grpc_call(id)
        do_chores(response)

    async def get_httpapi_info_and_do_chores(id):
        # do things
        response = requests.get(URL)
        do_chores(response)

    async_tasks = []
    for element in list(params.list_of_things):
       async_tasks.append(loop.create_task(get_chan_info_and_do_chores(id)))
       async_tasks.append(loop.create_task(get_httpapi_info_and_do_chores(ch_id)))

    loop.run_until_complete(asyncio.gather(*async_tasks))

यह कैसे काम करता है सरल है। आप उन कार्यों की एक श्रृंखला बना रहे हैं, जिन्हें आप अतुल्यकालिक रूप से प्राप्त करना चाहते हैं, और फिर एक पाश को उन कार्यों को निष्पादित करने और पूरा होने पर बाहर निकलने के लिए कह रहे हैं। कोई अतिरिक्त पुस्तकालय रखरखाव की कमी के अधीन है, कार्यक्षमता की कोई कमी की आवश्यकता नहीं है।


2
अगर मैं सही तरीके से समझूं, तो यह GRPC और HTTP कॉल करते समय इवेंट लूप को ब्लॉक कर देगा? इसलिए यदि ये कॉल पूर्ण होने में सेकंड लेते हैं, तो आपका पूरा ईवेंट लूप सेकंड के लिए ब्लॉक हो जाएगा? इससे बचने के लिए, आपको जीआरपीसी या एचटीटीपी पुस्तकालयों का उपयोग करना होगा async। तब आप उदाहरण के लिए कर सकते हैं await response = requests.get(URL)। नहीं?
कोडर एनआर 23

दुर्भाग्य से, जब यह कोशिश कर रहा था, मैंने पाया कि चारों ओर एक आवरण बनाना requestsमुश्किल से (और कुछ मामलों में धीमा) है, केवल URL की सूची को समान रूप से कॉल करने की तुलना में। उदाहरण के लिए, एक समापन बिंदु के लिए अनुरोध करने पर 3 सेकंड लगते हैं, जो कि ऊपर की रणनीति का उपयोग करके 10 बार प्रतिक्रिया करने में लगभग 30 सेकंड लगते हैं। यदि आप सही asyncप्रदर्शन चाहते हैं , तो आपको कुछ का उपयोग करने की आवश्यकता है aiohttp
ड्रैगनबोजज

8

मुझे पता है कि यह थोड़ी देर के लिए बंद कर दिया गया है, लेकिन मुझे लगा कि अनुरोध पुस्तकालय पर निर्मित एक अन्य एसिंक्स समाधान को बढ़ावा देने के लिए यह उपयोगी हो सकता है।

list_of_requests = ['http://moop.com', 'http://doop.com', ...]

from simple_requests import Requests
for response in Requests().swarm(list_of_requests):
    print response.content

डॉक्स यहां हैं: http://pythonhosted.org/simple-requests/


@YSY किसी मुद्दे को पोस्ट करने के लिए स्वतंत्र महसूस करें: github.com/ctheiss/simple-requests/issues ; मैं सचमुच इस पुस्तकालय का उपयोग दिन में हजारों बार करता हूं।
बंदर बोसॉन

बोस्टन, आप 404/500 त्रुटियों को कैसे संभालते हैं? https यूआरएल के बारे में क्या? एक स्निपिंग की सराहना करेंगे जो हजारों url का समर्थन करता है। क्या आप कृपया एक उदाहरण चिपका सकते हैं? धन्यवाद
YSY

@YSY डिफ़ॉल्ट रूप से 404/500 त्रुटियां एक अपवाद को बढ़ाती हैं। इस व्यवहार को ओवरराइड किया जा सकता है (देखें pythonhosted.org/simple-requests/… )। एचटीटीपीएस यूरिल्स पर निर्भरता के कारण मुश्किल है, जो वर्तमान में इस पर बकाया बग है ( github.com/gevent/gevent/issues/477 )। टिकट में एक शिम है जिसे आप चला सकते हैं, लेकिन यह अभी भी एसएनआई सर्वर के लिए चेतावनी फेंक देगा (लेकिन यह काम करेगा )। स्निपिंग के लिए, मुझे डर है कि मेरे सभी usages मेरी कंपनी में हैं और बंद हो गए हैं। लेकिन मैं आपको आश्वासन देता हूं कि हम दसियों नौकरियों के हजारों अनुरोधों पर अमल करते हैं।
मंकी बोसोन

पुस्तकालय बातचीत के संबंध में चिकना दिखता है। पायथन 3 + प्रयोग करने योग्य है? सॉरी कोई उल्लेख नहीं देख सका।
इसहाक फिलिप

@ जेथरो बिल्कुल सही है, लाइब्रेरी को कुल री-राइट की आवश्यकता होगी क्योंकि अंतर्निहित तकनीकें पायथन 3 में काफी भिन्न हैं। अभी के लिए, पुस्तकालय "पूर्ण" है, लेकिन केवल पायथन 2 के लिए काम करता है
बंदर बोसॉन

4
threads=list()

for requestURI in requests:
    t = Thread(target=self.openURL, args=(requestURI,))
    t.start()
    threads.append(t)

for thread in threads:
    thread.join()

...

def openURL(self, requestURI):
    o = urllib2.urlopen(requestURI, timeout = 600)
    o...

4
यह थ्रेड्स में "सामान्य" अनुरोध है। बुरा उदाहरण नहीं है खरीद ऑफ विषय है।
निक

4

यदि आप asyncio का उपयोग करना चाहते हैं, तो इसके requests-asyncलिए async / प्रतीक्षित कार्यक्षमता प्रदान करता है requests- https://github.com/encode/requests/async


2
पुष्टि की, महान काम करता है। परियोजना पृष्ठ पर यह कहता है कि यह कार्य निम्नलिखित परियोजना से आगे निकल चुका है github.com/encode/httpx
nurettin

2

मैं कुछ समय के लिए गिथब के जिस्ट एपीआई के खिलाफ async कॉल के लिए अजगर अनुरोधों का उपयोग कर रहा हूं।

एक उदाहरण के लिए, यहां कोड देखें:

https://github.com/davidthewatson/flasgist/blob/master/views.py#L60-72

अजगर की यह शैली स्पष्ट उदाहरण नहीं हो सकती है, लेकिन मैं आपको आश्वासन दे सकता हूं कि कोड काम करता है। मुझे बताएं कि क्या यह आपको भ्रमित कर रहा है और मैं इसे दस्तावेज करूंगा।


2

आप उसके httpxलिए उपयोग कर सकते हैं ।

import httpx

async def get_async(url):
    async with httpx.AsyncClient() as client:
        return await client.get(url)

urls = ["http://google.com", "http://wikipedia.org"]

# Note that you need an async context to use `await`.
await asyncio.gather(*map(get_async, urls))

यदि आप एक कार्यात्मक वाक्यविन्यास चाहते हैं, तो Gamla lib इसमें हो जाता हैget_async

तब आप कर सकते हैं


await gamla.map(gamla.get_async(10), ["http://google.com", "http://wikipedia.org"])

10सेकंड में समय समाप्ति है।

(अस्वीकरण: मैं इसका लेखक हूं)



0

मैंने अजगर में अतुल्यकालिक तरीकों का उपयोग करके कुछ चीजों की भी कोशिश की है, कैसे मैंने कभी भी अतुल्यकालिक प्रोग्रामिंग के लिए मुड़ का उपयोग करके बेहतर भाग्य पाया है। इसकी समस्याएं कम हैं और यह अच्छी तरह से प्रलेखित है। यहाँ कुछ सिम्मिलर की एक कड़ी है जिसे आप घुमा कर देख रहे हैं।

http://pythonquirks.blogspot.com/2011/04/twisted-asynchronous-http-request.html


मुड़ पुराने जमाने का है। इसके बजाय HTTPX का उपयोग करें।
अमीरहोसिन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.