2014-03-01 4 views
2

greenlets와 ThreadPool 스레드간에 공유 할 수있는 잠금을 만들 수있는 방법이 있습니까?ThreadPool 스레드간에 gevent 잠금/세마포를 공유 하시겠습니까?

특히, 내 응용 프로그램은 주로 gevent 기반이지만 일부는 "실제"스레드에서 실행해야합니다 ... 그러나 일부 작업 주위의 세마포를 사용하기 때문에 처리기와 관련된 문제가 발생합니다 :

 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 1300, in callHandlers 
    hdlr.handle(record) 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 742, in handle 
    self.acquire() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py", line 693, in acquire 
    self.lock.acquire() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 128, in acquire 
    rc = self.__block.acquire(blocking) 
    File "_semaphore.pyx", line 112, in gevent._semaphore.Semaphore.acquire (gevent/gevent._semaphore.c:2984) 
    File "…/gevent/hub.py", line 331, in switch 
    return greenlet.switch(self) 
LoopExit: This operation would block forever 

이 스레드 이 잠금을 보유하는 경우, 다음을 취득하려고B 스레드, 나는 의심 일어나고있다. 자물쇠가 이미 보유되고 있음을 알면 스레드 Bhub.switch()에 시도하지만 ... hub 스레드에 하나의 미성년자가 있으므로 "영원히 차단"예외가 발생합니다.

그래서! 이것에 대해 할 수있는 일이 있습니까? 아니면 내가 붙어 있니?

+0

매우 비슷한 문제가 발생했습니다. https://github.com/numba/numba/issues/1556. 실제로이 문제에 대한 해결책을 제시하는 것이 좋을 것입니다. – Michael

답변

0

이 코드 스 니펫이 풀로 간주되는지 확신 할 수 없습니다. 그러나 이것을 확인하십시오.

gevent의 모든 지점은 비동기입니다. 예를 들어, gevent없이 100 html 페이지를 요청해야하는 경우. 당신은 첫 번째 페이지에 첫 번째 요청을하고 파이썬 인터프리터는 응답이 준비 될 때까지 고정됩니다. 따라서 gevent는 첫 번째 요청의 출력을 중단하고 두 번째로 이동하여 시간을 낭비하지 않도록합니다. 그래서 우리는 여기서 원숭이 패치를 쉽게 할 수 있습니다. 그러나 요청 결과를 데이터베이스에 작성해야하는 경우 (예 : couchdb, couchdb에는 개정이 있으므로 문서를 동 기적으로 수정해야 함). 여기서 우리는 세마포어를 사용할 수 있습니다.

은 (동기 예는 여기에) 어떤 망할 코드를 만들 수 있습니다 :

from gevent import monkey 
monkey.patch_all() 

import gevent 
import os 
import requests 

from gevent.lock import Semaphore 
import time 

start = time.time() 

path = os.path.dirname(os.path.abspath(__file__)) 
gevent_lock = Semaphore() 

test_sites = [ 
    'https://vimeo.com/', 
    'https://stackoverflow.com/questions/22108576/share-gevent-locks-semaphores-between-threadpool-threads', 
    'http://www.gevent.org/gevent.monkey.html#gevent.monkey.patch_all', 
    'https://www.facebook.com/', 
    'https://twitter.com/', 
    'https://www.youtube.com/', 
    'https://zaxid.net/', 
    'https://24tv.ua/', 
    'https://zik.ua/', 
    'https://github.com/' 
] 

# request each site and write request status into file 
def process_each_page(html_page): 
    # here we dont need lock 
    response = requests.get(html_page) 

    gevent_lock.acquire() 
    with open(path + '/results.txt', 'a') as results_file: 
     results_file.write(str(response.status_code) + ' ' +html_page +'\n') 
    gevent_lock.release() 


gevent_greenlets = [gevent.spawn(process_each_page, page) for page in test_sites] 
gevent.joinall(gevent_greenlets) 
print(time.time() - start) 

지금 출력 파일을 발견 할 수 있습니다 :

import os 
import requests 
import time 

start = time.time() 
path = os.path.dirname(os.path.abspath(__file__)) 

test_sites = [ 
    'https://vimeo.com/', 
    'https://stackoverflow.com/questions/22108576/share-gevent-locks-semaphores-between-threadpool-threads', 
    'http://www.gevent.org/gevent.monkey.html#gevent.monkey.patch_all', 
    'https://www.facebook.com/', 
    'https://twitter.com/', 
    'https://www.youtube.com/', 
    'https://zaxid.net/', 
    'https://24tv.ua/', 
    'https://zik.ua/', 
    'https://github.com/' 
] 

# request each site and write request status into file 
def process_each_page(html_page): 
    # all requests are executed synchronously 
    response = requests.get(html_page) 
    with open(path + '/results_no_sema.txt', 'a') as results_file: 
     results_file.write(str(response.status_code) + ' ' +html_page +'\n') 

for page in test_sites: 
    process_each_page(page) 

print(time.time() - start) 

여기 gevent이 관련되고 아날로그 코드입니다. 이것은 동기 결과입니다.

enter image description here

는 그리고 이것은 gevent이 포함 된 스크립트입니다. enter image description here

gevent가 사용되었을 때 알 수 있듯이 응답이 순서대로 제공되지 않았습니다. 따라서 누구의 응답이 먼저 왔는지 먼저 파일로 기록되었습니다. 주요 부분은 gevent가 사용되었을 때 우리가 저장 한 시간을 볼 수 있습니다.

enter image description here

NOTA-BENE이 예에서 우리는 파일에 (추가)를 작성 잠글 필요가없는 위. 그러나 couchdb의 경우이 작업이 필요합니다. 따라서 get-save 문서로 couchdb와 함께 Semaphore를 사용하면 문서 충돌이 발생하지 않습니다!