2016-12-23 4 views
0

반환 된 json 데이터를 기반으로 항목 위치를 가져 오는 URL 범위를 반복하는 스크립트가 있습니다. 그러나 스크립트는 실행하는 데 60 분이 걸리지 만 json 데이터로드를 기다리는 동안 (cprofile 당) 55 분이 소요됩니다.파이썬 루프를 사용한 멀티 스레딩/멀티 프로세싱

속도를 높이기 위해 한 번에 여러 POST 요청을 실행하려면 멀티 스레드하고 싶습니다. 처음에는이 작업을 수행하기 위해 URL 범위를 두 개로 나눕니다. 내가 멈추고있는 곳은 멀티 쓰레딩이나 asyncio를 구현하는 방법이다.

몸매는 여전 하구나 코드 :

import asyncio 
import aiohttp 

# i am not recommend to use globals 
results = dict() 
url = "https://www.website.com/store/ajax/search" 
query = "store={}&size=18&query=17360031" 

# this is default url opener got from aiohttp documentation 
async def open_url(store, loop=None): 
    async with aiohttp.ClientSession(loop=loop) as session: 
     async with session.post(url, data={'searchQuery': query.format(store)}) as resp: 
      return await resp.json(), store 

async def processing(loop=None): 
    # U need to use 'global' keyworld if U wan't to write to global variables 
    global results 
    # one of the simplest ways to parallelize requests, is to init Future, and when data will be ready save it to global 
    tasks = [open_url(store, loop=event_loop) for store in range(0, 5)] 
    for coro in asyncio.as_completed(tasks, loop=loop): 
     try: 
      data, store = await coro 
      results[store] = data['searchResults']['results'][0]['location']['aisle'] 
     except (IndexError, KeyError): 
      continue 


if __name__ == '__main__': 
    event_loop = asyncio.new_event_loop() 
    event_loop.run_until_complete(processing(loop=event_loop)) 

# Print Results 
for store, data in results.items(): 
    print(store, data) 

JSON : JSON 데이터가 검색 될 때까지

{u'count': 1, 
    u'results': [{u'department': {u'name': u'Home', u'storeDeptId': -1}, 
      u'location': {u'aisle': [A], u'detailed': [A.536]}, 
      u'score': u'0.507073'}], 
    u'totalCount': 1} 

답변

0

당신이 멀티 스레딩 또는 멀티를 사용하는 경우에도, 각 스레드/프로세스가 계속 차단합니다. 이것은 약간의 작업 속도를 높일 수 있지만 여전히 최선의 선택은 아닙니다.

요청을 사용 중이므로 grequestsgevent을 조합 해보십시오. 이를 통해 비동기 적으로 실행되는 일련의 HTTP 요청을 정의 할 수 있습니다. 결과적으로 엄청난 속도 향상을 얻을 수 있습니다. 사용법은 매우 간단합니다. (grequests.get을 사용하여) 요청 목록을 만들고이를 grequests.map으로 전달하십시오.

희망이 도움이됩니다.

+0

감사합니다. 비동기 적으로 실행하는 것이 이상적 일 것입니다. grequests에 제공된 예제를 살펴 보았지만 특별히 URL 목록을 정의합니다. 위의 코드를 적용하는 방법을 놓친거야? 또한 grerequests.get 대신 grequests.post를 사용합니까? –

0

요청을 병렬화 할 수 없다면 (나는 이것을 묻습니다.) 이 코드 스 니펫이 도움이 될 것입니다. aiohttp 및 asyncio를 통해 전송 된 요청 시작 및 2000 개의 게시물 요청이 있습니다. python3.5 사용

import asyncio 
import aiohttp 

# i am not recommend to use globals 
results = dict() 
MAX_RETRIES = 5 
MATCH_SLEEP_TIME = 3 # i am recommend U to move this variables to other file like constants.py or any else 
url = "https://www.website.com/store/ajax/search" 
query = "store={}&size=18&query=44159" 

# this is default url opener got from aiohttp documentation 
async def open_url(store, semaphore, loop=None): 
    for _ in range(MAX_RETRIES): 
     with await semarhore: 
      try: 
       async with aiohttp.ClientSession(loop=loop) as session: 
        async with session.post(url, data={'searchQuery': query.format(store)}) as resp: 
         return await resp.json(), store 
      except ConnectionResetError: 
       # u can handle more exceptions here, and sleep if they are raised 
       await asyncio.sleep(MATCH_SLEEP_TIME, loop=loop) 
       continue 
    return None 

async def processing(semaphore, loop=None): 
    # U need to use 'global' keyworld if U wan't to write to global  variables 
    global results 
    # one of the simplest ways to parallelize requests, is to init  Future, and when data will be ready save it to global 
    tasks = [open_url(store, semaphore, loop=event_loop) for store in range(0,  2000)] 
    for coro in asyncio.as_completed(tasks, loop=loop): 
     try: 
      response = await coro 
      if response is None: 
       continue 
      data, store = response 
      results[store] = data['searchResults']['results'][0]['location']['aisle'] 
     except (IndexError, KeyError): 
      continue 


if __name__ == '__main__': 
    event_loop = asyncio.new_event_loop() 
    semaphore = asyncio.Semaphore(50, loop=event_loop) # count of concurrent requests 
    event_loop.run_until_complete(processing(semaphore, loop=event_loop)) 
+0

"NameError : name 'store'가 정의되지 않았습니다."를 실행하려고합니다. 나는 원래 게시물에 대해 몇 가지 업데이트를 만들었으며 "query ="store = {} & size = 18 & query = 44159 " "및 "data = json.loads (r.json() 'searchResults']) [ 'results'] [0] '이 (가) 귀하의 수정본에서 처리됩니다. 감사! –

+0

@MiaElla 안녕하세요, 내 대답을 업데이 트하지만 응답에서 HTML을 얻을, 아니 json, 확실 해요, 올바른 URL을? json 디코딩 오류를 피하기 위해 ** json.decoder.JSONDecodeError **를 제외하고는 u를 권장합니다. 또한 setdefault 또는 defaultdict를 사용하는 것이 좋습니다. –

+0

정확합니다.이 테스트에서는 웹 사이트 이름이 수정되었습니다. 난 여전히 오류가 발생했습니다 : File "C :/Users ... test.py", 34 행, event_loop.run_until_complete (processing (loop = event_loop)) line 387 in run_until_complete 처리 결과 _step = coro.send (없음) 라인 27에서, 결과 인상 self._exception 라인 (239)에서, results.setdefault (가기 [])를 future.result() 라인 (274)를 반환한다. 추가 (데이터 [ 'searchResults'] [ 'results'] [0] [ 'location'] [ 'aisle']) –

관련 문제