0X00 threading
Python的多线程库,虽然py的多线程在CPU密集型操作场景下是个垃圾,但是在IO密集型的场景下还是能显著提升效率的。关于threading的介绍可以查阅文档,这篇博客也不错:
https://blog.csdn.net/Xin_101/article/details/86593151
使用方式一般有两种,一种是创建threading.Thread实例,传入要绑定该线程的函数,然后进行执行。另一种就是继承threading.Thread,编写自己的线程类,个人比较倾向于第二种,灵活性高。
方式1:
import threading
def func():
print "func running"
return
t = threading.Thread(target=func)
t.start()
方式2:
import threading
import time
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
# Do what you want
if __name__ == '__main__':
thread_instance = MyThread()
thread_instance.start() # 创建线程实例后需要调用start方法启动线程
Q1:为什么在MyThread类中定义的是run方法来执行操作,线程实例却调用的start方法?
start()方法进行了一些关于类的前置判断,例如__init__方法是否正常被实现,该线程是否只被调用了一次,并对异常进行捕获,总而言之,这就是运行线程的入口。
0X01 threaing+queue实现生产者消费者
1.生产者
import time
import Queue
from test_thread import MyThread
class Worker:
def __init__(self):
self.task_queue = Queue.Queue()
thread_instance = MyThread(self.task_queue)
thread_instance.start()
def run(self):
while True:
self.task_queue.put('Knock Knock!')
time.sleep(2)
if __name__ == '__main__':
worker = Worker()
worker.run()
Worker的__init__方法实例化了一个消息队列queue和一个子线程,当运行Worker的run方法,就会每隔两秒往消息队列推送knock knock消息。
2.消费者
import threading
import time
class MyThread(threading.Thread):
def __init__(self, task_queue):
threading.Thread.__init__(self)
self.task_queue = task_queue
def run(self):
while True:
if not self.task_queue.empty():
msg = self.task_queue.get(timeout=1)
print msg
else:
time.sleep(1)
继承于基础的threading.Thread类,在__ini__方法中接收一个消息队列:self.task_queue,一旦该队列存在数据,就执行相应操作。
3.多消费者场景
如果需要多个消费者,那么实例化多个子线程即可,例如:
import time
import Queue
from test_thread import MyThread
class Worker:
def __init__(self):
self.task_queue = Queue.Queue()
t1 = MyThread(self.task_queue)
t1.start()
t2 = MyThread(self.task_queue)
t2.start()
t3 = MyThread(self.task_queue)
t3.start()
def run(self):
while True:
self.task_queue.put('Knock Knock!')
time.sleep(2)
if __name__ == '__main__':
worker = Worker()
worker.run()
注意:多线程操作共享数据时,注意数据安全问题,可使用加锁等方式。