如果使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue()来完成进程间的通信,而不是multiprocessing.Queue(),否则会抛出如下异常。RuntimeError: Queue objects should only be shared between processes through inheritance
from multiprocessing import Manager,Pool
import time
def write(q):
#将列表中的元素写入队列中
for i in ["a","b","c"]:
print('开始写入值%s' % i)
q.put(i)
time.sleep(1)
#读取
def read(q):
print('开始读取')
while True:
if not q.empty():
print('读取到:',q.get())
time.sleep(1)
else:
break
if __name__=='__main__':
#创建队列
q=Manager().Queue()
#创建进程池
p=Pool(3)
#使用阻塞模式创建进程
p.apply(write,(q,))
p.apply(read,(q,))
p.close()
p.join()
线程:
进程和线程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护,而进程正相反。
在Python程序中,可以通过“_thread”和threading(推荐使用)这两个模块来处理线程。在Python3中,thread模块已经废弃。可以使用threading模块代替。所以,在Python3中不能再使用thread模块,但是为了兼容Python3以前的程序,在Python3中将thread模块重命名为“_thread”。
在Python程序中,可以通过两种方式来使用线程:使用函数或者使用类来包装线程对象。当使用thread模块来处理线程时,可以调用里面的函数start_new_thread()来生成一个新的线程,语法格式如下:
_thread.start_new_thread ( function, args[, kwargs] ) |
其中function是线程函数;args表示传递给线程函数的参数,他必须是个tuple类型;kwargs 是可选参数。
threading模块
Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。
threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:
- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
- threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
在Python3程序中,对多线程支持最好的是threading模块,使用这个模块,可以灵活地创建多线程程序,并且可以在多线程之间进行同步和通信。在Python3程序中,可以通过如下两种方式来创建线程:
- 通过threading.Thread直接在线程中运行函数
- 通过继承类threading.Thread来创建线程
在Python中使用threading.Thread的基本语法格式如下所示:
Thread(group=None, target=None, name=None, args=(), kwargs={}) |
其中target: 要执行的方法;name: 线程名;args/kwargs: 要传入方法的参数。
import threading
import time
def fun1(thread_name,delay):
print('线程{0}开始运行fun1'.format(thread_name))
time.sleep(delay)
print('线程{0}运行fun1结束'.format(thread_name))
def fun2(thread_name,delay):
print('线程{0}开始运行fun2'.format(thread_name))
time.sleep(delay)
print('线程{0}运行fun2结束'.format(thread_name))
if __name__=='__main__':
print('开始运行')
#创建线程
t1=threading.Thread(target=fun1,args=('thread-1',4))
t2=threading.Thread(target=fun2,args=('thread-2',2))
t1.start()
t2.start()
在Python中,通过继承类threading.Thread的方式来创建一个线程。这种方法只要重写类threading.Thread中的方法run(),然后再调用方法start()就能创建线程,并运行方法run()中的代码。
【示例】继承threading.Thread类创建线程
import threading
import time
def fun1(delay):
print('线程{0}开始运行fun1'.format(threading.current_thread().getName))
time.sleep(delay)
print('线程{0}运行fun1结束'.format(threading.current_thread().getName))
def fun2(delay):
print('线程{0}开始运行fun2'.format(threading.current_thread().getName))
time.sleep(2)
print('线程{0}运行fun2结束'.format(threading.current_thread().getName))
#创建线程类继承threading.Thread
class MyThread(threading.Thread):
#重写父类的构造方法,其中func是线程函数,args是传入线程的参数,name是线程名
def __init__(self,func,name,args):
super().__init__(target=func,name=name,args=args)
#重写父类的run()方法
def run(self):
self._target(*self._args)
if __name__=='__main__':
print('开始运行')
#创建线程
t1=MyThread(fun1,'thread-1',(2,))
t2=MyThread(fun2,'thread-2',(4,))
t1.start()
t2.start()
互斥锁
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。最简单的同步机制就是引入互斥锁。
锁有两种状态——锁定和未锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”状态,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
使用 Thread 对象的 Lock 可以实现简单的线程同步,有上锁 acquire 方法和 释放release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。
【示例】互斥锁
import time
from threading import Thread,Lock
#定义全局变量num
num=0
#创建一把互斥锁
mutex=Lock()
def test1():
global num
'''
在两个线程中都调用上锁的方法,则这两个线程就会抢着上锁,
如果有1方成功上锁,那么导致另外一方会堵塞(一直等待)直到这个锁被解开
'''
mutex.acquire()#上锁
for i in range(100000):
num+=1
mutex.release()
print('test1输出num:',num)
def test2():
global num
mutex.acquire() # 上锁
for i in range(100000):
num+=1
mutex.release()
print('test2输出num:',num)
if __name__=='__main__':
t1=Thread(target=test1)
t2=Thread(target=test2)
t1.start()
t2.start()
t1.join()
t2.join()