Python 30 行代码实现小型多线程任务队列
admin
2023-07-31 00:38:49
0

最近我在用梯度下降算法绘制神经网络的数据时,遇到了一些算法性能的问题。梯度下降算法的代码如下(伪代码):

123 def gradient_descent():    # the gradient descent code    plotly.write(X, Y)

一般来说,当网络请求 plot.ly 绘图时会阻塞等待返回,于是也会影响到其他的梯度下降函数的执行速度。

一种解决办法是每调用一次 plotly.write 函数就开启一个新的线程,但是这种方法感觉不是很好。 我不想用一个像 cerely(一种分布式任务队列)一样大而全的任务队列框架,因为框架对于我的这点需求来说太重了,并且我的绘图也并不需要 redis 来持久化数据。

那用什么办法解决呢?我在 python 中写了一个很小的任务队列,它可以在一个单独的线程中调用 plotly.write函数。下面是程序代码。

12345 from threading import Threadimport Queue import time class TaskQueue(Queue.Queue):

首先我们继承 Queue.Queue 类。从 Queue.Queue 类可以继承 get 和 put 方法,以及队列的行为。

1234 def __init__(self, num_workers=1):    Queue.Queue.__init__(self)    self.num_workers = num_workers    self.start_workers()

初始化的时候,我们可以不用考虑工作线程的数量。

1234 def add_task(self, task, *args, **kwargs):    args = args or ()    kwargs = kwargs or {}    self.put((task, args, kwargs))

我们把 task, args, kwargs 以元组的形式存储在队列中。*args 可以传递数量不等的参数,**kwargs 可以传递命名参数。

12345 def start_workers(self):    for i in range(self.num_workers):        t = Thread(target=self.worker)        t.daemon = True        t.start()

我们为每个 worker 创建一个线程,然后在后台删除。

下面是 worker 函数的代码:

123456 def worker(self):    while True:       tupl = self.get()       item, args, kwargs = self.get()       item(*args, **kwargs)        self.task_done()

worker 函数获取队列顶端的任务,并根据输入参数运行,除此之外,没有其他的功能。下面是队列的代码:

我们可以通过下面的代码测试:

123456789101112 def blokkah(*args, **kwargs):    time.sleep(5)    print Blokkah mofo!” q = TaskQueue(num_workers=5) for item in range(1):    q.add_task(blokkah) q.join() # wait for all the tasks to finish. print All done!

Blokkah 是我们要做的任务名称。队列已经缓存在内存中,并且没有执行很多任务。下面的步骤是把主队列当做单独的进程来运行,这样主程序退出以及执行数据库持久化时,队列任务不会停止运行。但是这个例子很好地展示了如何从一个很简单的小任务写成像工作队列这样复杂的程序。

123 def gradient_descent():    # the gradient descent code    queue.add_task(plotly.write, x=X, y=Y)

修改之后,我的梯度下降算法工作效率似乎更高了。如果你很感兴趣的话,可以参考下面的代码。

1234567891011121314151617181920212223242526272829303132333435363738394041424344 from threading import Threadimport Queueimport time class TaskQueue(Queue.Queue): def __init__(self, num_workers=1):Queue.Queue.__init__(self)self.num_workers = num_workersself.start_workers() def add_task(self, task, *args, **kwargs):args = args or ()kwargs = kwargs or {}self.put((task, args, kwargs)) def start_workers(self):for i in range(self.num_workers):t = Thread(target=self.worker)t.daemon = Truet.start() def worker(self):while True:tupl = self.get()item, args, kwargs = self.get()item(*args, **kwargs)self.task_done() def tests():def blokkah(*args, **kwargs):time.sleep(5)print \”Blokkah mofo!\” q = TaskQueue(num_workers=5) for item in range(10):q.add_task(blokkah) q.join() # block until all tasks are doneprint \”All done!\” if __name__ == \”__main__\”:tests()

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
python清除字符串里非数字... 本文实例讲述了python清除字符串里非数字字符的方法。分享给大家供大家参考。具体如下: impor...