Python实现简单多线程任务队列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python实现简单多线程任务队列相关的知识,希望对你有一定的参考价值。

Python实现简单多线程任务队列最近我在用梯度下降算法绘制神经网络的数据时,遇到了一些算法性能的问题。梯度下降算法的代码如下(伪代码)

参考技术A Python实现简单多线程任务队列
最近我在用梯度下降算法绘制神经网络的数据时,遇到了一些算法性能的问题。梯度下降算法的代码如下(伪代码):
defgradient_descent(): # the gradient descent code plotly.write(X, Y)
一般来说,当网络请求 plot.ly 绘图时会阻塞等待返回,于是也会影响到其他的梯度下降函数的执行速度。
一种解决办法是每调用一次 plotly.write 函数就开启一个新的线程,但是这种方法感觉不是很好。 我不想用一个像 cerely(一种分布式任务队列)一样大而全的任务队列框架,因为框架对于我的这点需求来说太重了,并且我的绘图也并不需要 redis 来持久化数据。
那用什么办法解决呢?我在 python 中写了一个很小的任务队列,它可以在一个单独的线程中调用 plotly.write函数。下面是程序代码。
fromthreadingimportThreadimportQueueimporttime classTaskQueue(Queue.Queue):
首先我们继承 Queue.Queue 类。从 Queue.Queue 类可以继承 get 和 put 方法,以及队列的行为。
def__init__(self, num_workers=1): Queue.Queue.__init__(self) self.num_workers=num_workers self.start_workers()
初始化的时候,我们可以不用考虑工作线程的数量。
defadd_task(self, task,*args,**kwargs): args=argsor() kwargs=kwargsor self.put((task, args, kwargs))
我们把 task, args, kwargs 以元组的形式存储在队列中。*args 可以传递数量不等的参数,**kwargs 可以传递命名参数。
defstart_workers(self): foriinrange(self.num_workers): t=Thread(target=self.worker) t.daemon=True t.start()
我们为每个 worker 创建一个线程,然后在后台删除。
下面是 worker 函数的代码:
defworker(self): whileTrue: tupl=self.get() item, args, kwargs=self.get() item(*args,**kwargs) self.task_done()
worker 函数获取队列顶端的任务,并根据输入参数运行,除此之外,没有其他的功能。下面是队列的代码:
我们可以通过下面的代码测试:
defblokkah(*args,**kwargs): time.sleep(5) print“Blokkah mofo!” q=TaskQueue(num_workers=5) foriteminrange(1): q.add_task(blokkah) q.join()# wait for all the tasks to finish. print“Alldone!”
Blokkah 是我们要做的任务名称。队列已经缓存在内存中,并且没有执行很多任务。下面的步骤是把主队列当做单独的进程来运行,这样主程序退出以及执行数据库持久化时,队列任务不会停止运行。但是这个例子很好地展示了如何从一个很简单的小任务写成像工作队列这样复杂的程序。
defgradient_descent(): # the gradient descent code queue.add_task(plotly.write, x=X, y=Y)
修改之后,我的梯度下降算法工作效率似乎更高了。如果你很感兴趣的话,可以参考下面的代码。fromthreadingimportThreadimportQueueimporttime classTaskQueue(Queue.Queue): def__init__(self, num_workers=1):Queue.Queue.__init__(self)self.num_workers=num_workersself.start_workers() defadd_task(self, task,*args,**kwargs):args=argsor()kwargs=kwargsorself.put((task, args, kwargs)) defstart_workers(self):foriinrange(self.num_workers):t=Thread(target=self.worker)t.daemon=Truet.start() defworker(self):whileTrue:tupl=self.get()item, args, kwargs=self.get()item(*args,**kwargs)self.task_done() deftests():defblokkah(*args,**kwargs):time.sleep(5)print"Blokkah mofo!" q=TaskQueue(num_workers=5) foriteminrange(10):q.add_task(blokkah) q.join()# block until all tasks are doneprint"All done!" if__name__=="__main__":tests()

Python 用队列实现多线程并发

# Python queue队列,实现并发,在网站多线程推荐最后也一个例子,比这货简单,但是不够规范

# encoding: utf-8
__author__ = yeayee.com  # 由本站增加注释,可随意Fork、Copy

from queue import Queue  # Queue在3.x中改成了queue
import random
import threading
import time


class Producer(threading.Thread):
    """
    Producer thread 制作线程
    """
    def __init__(self, t_name, queue):  # 传入线程名、实例化队列
        threading.Thread.__init__(self, name=t_name)  # t_name即是threadName
        self.data = queue

    """
    run方法 和start方法:
    它们都是从Thread继承而来的,run()方法将在线程开启后执行,
    可以把相关的逻辑写到run方法中(通常把run方法称为活动[Activity]);
    start()方法用于启动线程。
    """

    def run(self):
        for i in range(5):  # 生成0-4五条队列
            print("%s: %s is producing %d to the queue!" % (time.ctime(), self.getName(), i))  # 当前时间t生成编号d并加入队列
            self.data.put(i)  # 写入队列编号
            time.sleep(random.randrange(10) / 5)  # 随机休息一会
        print("%s: %s producing finished!" % (time.ctime(), self.getName))  # 编号d队列完成制作


class Consumer(threading.Thread):
    """
    Consumer thread 消费线程,感觉来源于COOKBOOK
    """
    def __init__(self, t_name, queue):
        threading.Thread.__init__(self, name=t_name)
        self.data = queue

    def run(self):
        for i in range(5):
            val = self.data.get()
            print("%s: %s is consuming. %d in the queue is consumed!" % (time.ctime(), self.getName(), val))  # 编号d队列已经被消费
            time.sleep(random.randrange(10))
        print("%s: %s consuming finished!" % (time.ctime(), self.getName()))  # 编号d队列完成消费


def main():
    """
    Main thread 主线程
    """
    queue = Queue()  # 队列实例化
    producer = Producer(Pro., queue)  # 调用对象,并传如参数线程名、实例化队列
    consumer = Consumer(Con., queue)  # 同上,在制造的同时进行消费
    producer.start()  # 开始制造
    consumer.start()  # 开始消费
    """
    join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
  join()方法的位置是在for循环外的,也就是说必须等待for循环里的两个进程都结束后,才去执行主进程。
    """
    producer.join()
    consumer.join()
    print(All threads terminate!)


if __name__ == __main__:
    main()


"""运行结果:

Thu Feb  4 11:05:48 2016: Pro. is producing 0 to the queue!
Thu Feb  4 11:05:48 2016: Pro. is producing 1 to the queue!
Thu Feb  4 11:05:48 2016: Con. is consuming. 0 in the queue is consumed!
Thu Feb  4 11:05:49 2016: Pro. is producing 2 to the queue!
Thu Feb  4 11:05:50 2016: Pro. is producing 3 to the queue!
Thu Feb  4 11:05:51 2016: Pro. is producing 4 to the queue!
Thu Feb  4 11:05:52 2016: Con. is consuming. 1 in the queue is consumed!
Thu Feb  4 11:05:53 2016: <bound method Producer.getName of <Producer(Pro., started 6864)>> producing finished!
Thu Feb  4 11:06:00 2016: Con. is consuming. 2 in the queue is consumed!
Thu Feb  4 11:06:06 2016: Con. is consuming. 3 in the queue is consumed!
Thu Feb  4 11:06:06 2016: Con. is consuming. 4 in the queue is consumed!
Thu Feb  4 11:06:12 2016: Con. consuming finished!
All threads terminate!

"""

 

以上是关于Python实现简单多线程任务队列的主要内容,如果未能解决你的问题,请参考以下文章

python多线程并行计算通过向线程池ThreadPoolExecutor提交任务的实现方法

python 多进程和多线程3 —— asyncio - 异步IO

python 多进程和多线程3 —— asyncio - 异步IO

Celery分布式队列学习

python端口扫描用多线程+线程安全的队列+Thread类实现

python 多线程与队列