有没有办法制作一个可以在greenlets和ThreadPool线程之间共享的锁?
具体来说,我的应用程序主要基于 gevent,但有些部分需要在“真实”线程中运行……但这会导致 logging
处理程序出现问题,因为它们在某些操作周围使用信号量,产生类似于以下内容的异常:
文件“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py”,第 1300 行,在 callHandlers 中
hdlr.handle(记录)
文件“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py”,第 742 行,在句柄中
self.acquire()
文件“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.py”,第 693 行,在获取中
self.lock.acquire()
文件“/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py”,第 128 行,在获取中
rc = self.__block.acquire(阻塞)
文件“_semaphore.pyx”,第 112 行,在 gevent._semaphore.Semaphore.acquire (gevent/gevent._semaphore.c:2984)
文件“.../gevent/hub.py”,第 331 行,在 switch 中
返回 greenlet.switch(self)
LoopExit:此操作将永远阻塞
我怀疑,当线程 A 持有锁时,会发生这种情况,然后线程 B 尝试获取它。在注意到锁已经被持有时,线程 B 尝试 hub.switch()
……但由于线程 B 的 hub
中只有一个 greenlet,因此引发了“永远阻塞”异常。
所以!有什么可以做的吗?还是我卡住了?
最佳答案
我无法确定此代码片段是否被视为池。但是看看这个。
gevent 的所有重点是它是异步的。例如,如果您需要请求 100 个 html 页面(没有 gevent)。您向第一页发出第一个请求,并且您的 Python 解释器被卡住,直到响应准备就绪。所以 gevent 允许卡住第一个请求的输出并移动到第二个,这意味着不要浪费时间。
所以我们可以轻松地在这里修补所有内容。但是如果你需要把请求的结果写入数据库(比如couchdb,couchdb有修改,也就是说文档要同步修改)。这里我们可以使用信号量。
让我们编写一些该死的代码(这里是同步示例):
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 时,响应的顺序不正确。所以谁的响应先写在文件中。主要部分让我们看看使用 gevent 时我们节省了多少时间。
NOTA-BENE:在上面的示例中,我们不需要锁定写入(追加)到文件。但是对于 couchdb,这是必需的。因此,当您将 Semaphore 与 couchdb 与 get-save 文档一起使用时,您不会遇到文档冲突!
关于python - 在 ThreadPool 线程之间共享 gevent 锁/信号量?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22108576/