2015-08-22 12 views
7

में परिणाम जोड़ना मुझे पाइथन 3 की असिनियो लाइब्रेरी के आसपास अपना आगे लपेटने में परेशानी हो रही है। मेरे पास ज़ीपोड्स की एक सूची है और मैं प्रत्येक ज़िपकोड संबंधित शहर और राज्य प्राप्त करने के लिए एपीआई को एसिंक कॉल करने की कोशिश कर रहा हूं। मैं इसे लूप के साथ अनुक्रम में सफलतापूर्वक कर सकता हूं लेकिन मैं इसे एक बड़ी ज़िप कोड सूची के मामले में तेज़ी से बनाना चाहता हूं।एसिन्सीओ के साथ कई कॉल करना और परिणाम को

यह मेरा मूल का एक उदाहरण है कि काम करता है

import urllib.request, json 

zips = ['90210', '60647'] 

def get_cities(zipcodes): 
    zip_cities = dict() 
    for idx, zipcode in enumerate(zipcodes): 
     url = 'http://maps.googleapis.com/maps/api/geocode/json?address='+zipcode+'&sensor=true' 
     response = urllib.request.urlopen(url) 
     string = response.read().decode('utf-8') 
     data = json.loads(string) 
     city = data['results'][0]['address_components'][1]['long_name'] 
     state = data['results'][0]['address_components'][3]['long_name'] 
     zip_cities.update({idx: [zipcode, city, state]}) 
    return zip_cities 

results = get_cities(zips) 
print(results) 
# returns {0: ['90210', 'Beverly Hills', 'California'], 
#   1: ['60647', 'Chicago', 'Illinois']} 

यह async

import asyncio 
import urllib.request, json 

zips = ['90210', '60647'] 
zip_cities = dict() 

@asyncio.coroutine 
def get_cities(zipcodes): 
    url = 'http://maps.googleapis.com/maps/api/geocode/json?address='+zipcode+'&sensor=true' 
    response = urllib.request.urlopen(url) 
    string = response.read().decode('utf-8') 
    data = json.loads(string) 
    city = data['results'][0]['address_components'][1]['long_name'] 
    state = data['results'][0]['address_components'][3]['long_name'] 
    zip_cities.update({idx: [zipcode, city, state]}) 

loop = asyncio.get_event_loop() 
loop.run_until_complete([get_cities(zip) for zip in zips]) 
loop.close() 
print(zip_cities) # doesnt work 

किसी भी मदद के इसे बनाने के लिए बहुत सराहना कर रहा है की कोशिश कर रहा पर मेरे भयानक गैर कार्यात्मक प्रयास है। मेरे द्वारा ऑनलाइन आने वाले सभी ट्यूटोरियल मेरे सिर पर एक टैड लगते हैं।

नोट: मैंने कुछ उदाहरण aiohttp का उपयोग किया है। मैं संभवतः देशी पायथन 3 पुस्तकालयों के साथ चिपकने की उम्मीद कर रहा था।

उत्तर

7

यदि आप HTTP अनुरोध करने के लिए urllib का उपयोग करते हैं, तो आप कोई समरूपता प्राप्त करने में सक्षम नहीं होंगे, क्योंकि यह एक सिंक्रोनस लाइब्रेरी है। में coroutine में कॉल करने वाले फ़ंक्शन को लपेटना उसमें बदलाव नहीं करता है। आप एक अतुल्यकालिक HTTP ग्राहक कि asyncio में एकीकृत है, aiohttp की तरह उपयोग करने के लिए:

import asyncio 
import json 
import aiohttp 

zips = ['90210', '60647'] 
zip_cities = dict() 

@asyncio.coroutine 
def get_cities(zipcode,idx): 
    url = 'https://maps.googleapis.com/maps/api/geocode/json?key=abcdfg&address='+zipcode+'&sensor=true' 
    response = yield from aiohttp.request('get', url) 
    string = (yield from response.read()).decode('utf-8') 
    data = json.loads(string) 
    print(data) 
    city = data['results'][0]['address_components'][1]['long_name'] 
    state = data['results'][0]['address_components'][3]['long_name'] 
    zip_cities.update({idx: [zipcode, city, state]}) 

if __name__ == "__main__":   
    loop = asyncio.get_event_loop() 
    tasks = [asyncio.async(get_cities(z, i)) for i, z in enumerate(zips)] 
    loop.run_until_complete(asyncio.wait(tasks)) 
    loop.close() 
    print(zip_cities) 

मैं जानता हूँ कि आप केवल stdlib उपयोग करना पसंद करते हैं, लेकिन asyncio पुस्तकालय एक HTTP ग्राहक को शामिल नहीं करता है, तो आप चाहते हैं इसकी प्रदान करने वाली कार्यक्षमता को फिर से बनाने के लिए मूल रूप से aiohttp के टुकड़ों को फिर से कार्यान्वित करने के लिए। मुझे लगता है कि एक और विकल्प पृष्ठभूमि थ्रेड में urllib कॉल करना होगा, ताकि वे ईवेंट लूप को अवरुद्ध न करें, लेकिन aiohttp पर उपलब्ध होने के लिए मूर्खतापूर्ण तरीके (और asyncio का उपयोग करने के उद्देश्य को हरा देता है पहली जगह):

import asyncio 
import json 
import urllib.request 
from concurrent.futures import ThreadPoolExecutor 

zips = ['90210', '60647'] 
zip_cities = dict() 

@asyncio.coroutine 
def get_cities(zipcode,idx): 
    url = 'https://maps.googleapis.com/maps/api/geocode/json?key=abcdfg&address='+zipcode+'&sensor=true' 
    response = yield from loop.run_in_executor(executor, urllib.request.urlopen, url) 
    string = response.read().decode('utf-8') 
    data = json.loads(string) 
    print(data) 
    city = data['results'][0]['address_components'][1]['long_name'] 
    state = data['results'][0]['address_components'][3]['long_name'] 
    zip_cities.update({idx: [zipcode, city, state]}) 

if __name__ == "__main__": 
    executor = ThreadPoolExecutor(10) 
    loop = asyncio.get_event_loop() 
    tasks = [asyncio.async(get_cities(z, i)) for i, z in enumerate(zips)] 
    loop.run_until_complete(asyncio.wait(tasks)) 
    loop.close() 
    print(zip_cities) 
+0

इसके लिए धन्यवाद। 'Aiohttp' रास्ता बहुत साफ है। –

+2

@ एंथनी-डंड्रिया यदि आपकी ज़िप कोड सूची बड़ी हो रही है, तो मैं 100 कनेक्शन या उससे अधिक की तरह एक संख्या संख्या के साथ-साथ संख्या को सीमित करने की भी सिफारिश करता हूं, अन्यथा आप अवरुद्ध हो सकते हैं। * अनुभव से बात नहीं कर रहा; -] –

3

नहीं asyncio साथ बहुत कुछ किया लेकिन asyncio.get_event_loop() होना चाहिए कि तुम क्या जरूरत है, तो आप भी स्पष्ट रूप से बदल क्या आपके समारोह तर्कों के रूप लेता है और के रूप में प्रति docsasyncio.wait(tasks) उपयोग करने के लिए:

zips = ['90210', '60647'] 
zip_cities = dict() 

@asyncio.coroutine 
def get_cities(zipcode): 
    url = 'https://maps.googleapis.com/maps/api/geocode/json?key=abcdefg&address='+zipcode+'&sensor=true' 
    fut = loop.run_in_executor(None,urllib.request.urlopen, url) 
    response = yield from fut 
    string = response.read().decode('utf-8') 
    data = json.loads(string) 
    city = data['results'][0]['address_components'][1]['long_name'] 
    state = data['results'][0]['address_components'][3]['long_name'] 
    zip_cities.update({idx: [zipcode, city, state]}) 

loop = asyncio.get_event_loop() 
tasks = [asyncio.async(get_cities(z, i)) for i, z in enumerate(zips)] 
loop.run_until_complete(asyncio.wait(tasks)) 
loop.close() 
print(zip_cities) # doesnt work 
{0: ['90210', 'Beverly Hills', 'California'], 1: ['60647', 'Chicago', 'Illinois']} 

मेरे पास नहीं है>

@asyncio.coroutine 
def get_cities(zipcode): 
    url = 'https://maps.googleapis.com/maps/api/geocode/json?key=abcdefg&address='+zipcode+'&sensor=true' 
    fut = loop.run_in_executor(None,urllib.request.urlopen, url) 
    response = yield from fut 
    string = response.read().decode('utf-8') 
    data = json.loads(string) 
    city = data['results'][0]['address_components'][1]['long_name'] 
    state = data['results'][0]['address_components'][3]['long_name'] 
    return [zipcode, city, state] 

loop = asyncio.get_event_loop() 
tasks = [asyncio.async(get_cities(z)) for z in zips] 
loop.run_until_complete(asyncio.wait(tasks)) 
loop.close() 
zip_cities = {i:tsk.result() for i,tsk in enumerate(tasks)} 
print(zip_cities) 
{0: ['90210', 'Beverly Hills', 'California'], 1: ['60647', 'Chicago', 'Illinois']} 
: = 3.4.4 तो मैं asyncio.ensure_future

के बजाय asyncio.async का उपयोग या तर्क बदल सकते हैं और कार्यों से task.result से dict बनाने के लिए किया था

यदि आप बाहरी मॉड्यूल देख रहे हैं तो port of requests भी है जो एसिन्सीओ के साथ काम करता है।

+1

यह अभी भी तुल्यकालिक है, क्योंकि 'urllib.request.urlopen' ईवेंट लूप को अवरुद्ध कर देगा। – dano

+0

@ डैनो, हाँ, मैंने इसे अनदेखा किया, इसे काम करने के लिए एक बड़ा बदलाव नहीं। –

संबंधित मुद्दे