有没有办法制作一个可以在greenlets和ThreadPool线程之间共享的锁?
具体来说,我的应用程序主要是基于gevent的,但有些部分需要在“真正的”线程中运行......但这会导致logging
处理程序出现问题,因为它们在某些操作周围使用信号量,产生类似的异常到:
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
这种情况正在发生,我怀疑,当线程 A 持有锁时,线程 B 会尝试获取它。在注意到锁已被保持时,线程 B 尝试hub.switch()
...但由于线程中只有一个greenlet B 的hub
,提出了“永远阻止”的例外。
原来如此!有什么可以做的吗?还是我被卡住了?
答案 0 :(得分:2)
我无法确定此代码snipplet是否被视为池。但请检查一下。
gevent中的所有demn点都是异步的。例如,如果您需要请求100个html页面(没有gevent)。您首先向第一页请求,并且您的python解释器将被冻结,直到响应准备就绪。因此gevent允许冻结那些第一个请求的输出并移动到第二个,这意味着不要浪费时间。 所以我们可以轻松地在这里修补补丁。但是如果你需要将请求的结果写入数据库(例如couchdb,则couchdb有修订版,这意味着文档应该同步修改)。在这里我们可以使用Semaphore。
让我们做一些该死的代码(这是同步的例子):
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的模拟代码:
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)
现在让我们发现输出文件。这是同步的结果。
正如你所看到的那样,当使用gevent时,响应不是按顺序进行的。所以首先回复的是先写入文件。主要部分让我们看看在使用gevent时我们节省了多少时间。
NOTA-BENE:在上面的示例中,我们不需要锁定写入(追加)到文件。但对于couchdb,这是必需的。因此,当您使用带有获取保存文档的couchdb的Semaphore时,您不会获得文档冲突!