Python中的后台函数
- 2025-03-19 08:57:00
- admin 原创
- 52
问题描述:
我有一个 Python 脚本,有时会向用户显示图像。这些图像有时会非常大,而且经常被重复使用。显示它们并不重要,但显示与它们相关的消息很重要。我有一个函数可以下载所需的图像并将其保存在本地。现在它与向用户显示消息的代码内联运行,但对于非本地图像,这有时可能需要 10 秒以上。有没有办法在需要时调用此函数,但在代码继续执行时在后台运行它?我会使用默认图像,直到正确的图像可用。
解决方案 1:
做这样的事:
def function_that_downloads(my_args):
# do some long download here
然后内联,执行以下操作:
import threading
def my_inline_function(some_args):
# do some stuff
download_thread = threading.Thread(target=function_that_downloads, name="Downloader", args=some_args)
download_thread.start()
# continue doing stuff
您可能希望在继续执行其他操作之前检查线程是否已完成,方法是调用download_thread.isAlive()
解决方案 2:
通常,实现此目的的方法是使用线程池和队列下载,当该任务处理完毕时,它会发出信号(即事件)。您可以在 Python 提供的线程模块范围内执行此操作。
为了执行上述操作,我将使用事件对象和队列模块。
threading.Thread
但是,下面可以快速而粗略地演示一下使用简单实现可以做什么:
import os
import threading
import time
import urllib2
class ImageDownloader(threading.Thread):
def __init__(self, function_that_downloads):
threading.Thread.__init__(self)
self.runnable = function_that_downloads
self.daemon = True
def run(self):
self.runnable()
def downloads():
with open('somefile.html', 'w+') as f:
try:
f.write(urllib2.urlopen('http://google.com').read())
except urllib2.HTTPError:
f.write('sorry no dice')
print 'hi there user'
print 'how are you today?'
thread = ImageDownloader(downloads)
thread.start()
while not os.path.exists('somefile.html'):
print 'i am executing but the thread has started to download'
time.sleep(1)
print 'look ma, thread is not alive: ', thread.is_alive()
不进行轮询可能更有意义,就像我上面所做的那样。在这种情况下,我会将代码更改为:
import os
import threading
import time
import urllib2
class ImageDownloader(threading.Thread):
def __init__(self, function_that_downloads):
threading.Thread.__init__(self)
self.runnable = function_that_downloads
def run(self):
self.runnable()
def downloads():
with open('somefile.html', 'w+') as f:
try:
f.write(urllib2.urlopen('http://google.com').read())
except urllib2.HTTPError:
f.write('sorry no dice')
print 'hi there user'
print 'how are you today?'
thread = ImageDownloader(downloads)
thread.start()
# show message
thread.join()
# display image
请注意这里没有设置守护进程标志。
解决方案 3:
我更喜欢使用gevent来做这种事:
import gevent
from gevent import monkey; monkey.patch_all()
greenlet = gevent.spawn( function_to_download_image )
display_message()
# ... perhaps interaction with the user here
# this will wait for the operation to complete (optional)
greenlet.join()
# alternatively if the image display is no longer important, this will abort it:
#greenlet.kill()
所有东西都在一个线程中运行,但每当内核操作阻塞时,gevent 就会在其他“greenlet”运行时切换上下文。锁定等问题大大减少,因为一次只运行一个程序,但只要在“主”上下文中执行阻塞操作,图像就会继续下载。
根据您想要在后台执行多少操作以及执行哪种操作,这可能比基于线程的解决方案更好或更差;当然,它的可扩展性更强(即您可以在后台执行更多操作),但在当前情况下这可能并不令人担忧。
解决方案 4:
import threading
import os
def killme():
if keyboard.read_key() == "q":
print("Bye ..........")
os._exit(0)
threading.Thread(target=killme, name="killer").start()
如果要添加更多键,请多次添加def
s 和threading.Thread(target=killme, name="killer").start()
行。虽然看起来很糟糕,但效果比复杂的代码好得多。
扫码咨询,免费领取项目管理大礼包!