单线程:
import time
import threading
def music(name,loop):
for i in range(loop):
print("listen music {} {}".format(name,time.ctime()))
time.sleep(1)
def movie(name,loop):
for i in range(loop):
print("look movie {} {}".format(name,time.ctime()))
time.sleep(1)
if __name__ == "__main__":
music("爱转角",5)
movie("小王子",4)
print("end time",time.ctime())
多线程:
import time
import threading
def music(name,loop):
for i in range(loop):
print("listen music {} {}".format(name,time.ctime()))
time.sleep(1)
def movie(name,loop):
for i in range(loop):
print("look movie {} {}".format(name,time.ctime()))
time.sleep(1)
# 创建多线程
t1 = threading.Thread(target=music,args=("爱转角",5))
t2 = threading.Thread(target=movie,args=("小王子",4))
if __name__ == "__main__":
# 启动线程
t1.start()
t2.start()
# print("end time",time.ctime())
import time
import threading
def music(name,loop):
for i in range(loop):
print("listen music {} {} {}".format(name,time.ctime(),threading.Thread.getName(t1)))
time.sleep(1)
def movie(name,loop):
for i in range(loop):
print("look movie {} {} {}".format(name,time.ctime(),threading.Thread.name))
time.sleep(1)
# 创建多线程
t1 = threading.Thread(target=music,args=("爱转角",5))
t1.setName("线程1")
t2 = threading.Thread(target=movie,args=("小王子",4),)
# t2.setName("线程2")
if __name__ == "__main__":
# 启动线程
t1.start()
t2.start()
# print("end time",time.ctime())
look movie 小王子 Sat Jul 6 08:19:37 2019 <property object at 0x000002656EF79728>
listen music 爱转角 Sat Jul 6 08:19:38 2019 线程1
look movie 小王子 Sat Jul 6 08:19:38 2019 <property object at 0x000002656EF79728>
listen music 爱转角 Sat Jul 6 08:19:39 2019 线程1
look movie 小王子 Sat Jul 6 08:19:39 2019 <property object at 0x000002656EF79728>
look movie 小王子 Sat Jul 6 08:19:40 2019 <property object at 0x000002656EF79728>
listen music 爱转角 Sat Jul 6 08:19:40 2019 线程1
listen music 爱转角 Sat Jul 6 08:19:41 2019 线程1
线程守护,主线程结束,杀死子线程
import time
import threading
def music(name,loop):
for i in range(loop):
print("listen music {} {} {}".format(name,time.ctime(),threading.Thread.getName(t1)))
time.sleep(1)
def movie(name,loop):
for i in range(loop):
print("look movie {} {} {}".format(name,time.ctime(),threading.Thread.name))
time.sleep(1)
# 创建多线程
t1 = threading.Thread(target=music,args=("爱转角",5))
t1.setName("线程1")
t2 = threading.Thread(target=movie,args=("小王子",4),)
# t2.setName("线程2")
if __name__ == "__main__":
# 守护主线程 主线程结束,杀死子线程
t1.setDaemon(True)
t2.setDaemon(True)
# 启动线程
t1.start()
t2.start()
print("主线程:",time.ctime())
listen music 爱转角 Sat Jul 6 08:29:43 2019 线程1
look movie 小王子 Sat Jul 6 08:29:43 2019 <property object at 0x00000254F7629728>
主线程: Sat Jul 6 08:29:43 2019
GIL全局锁:相当于python 单线程,不适合大的数据量
import threading
balace =0
def change(n):
global balace
balace += n
balace -= n
lock = threading.Lock()#获取线程锁
def run_thread(n):
for i in range(1000000):
#获取锁
lock.acquire()
try:
change(n)
finally:
# 释放锁
lock.release()
t1 = threading.Thread(target=run_thread,args=(4,))
t2 = threading.Thread(target=run_thread,args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balace)
多进程及加锁:
import time
import multiprocessing
def music(name,loop,lock):
lock.acquire()
for i in range(loop):
print("listen music {} {}".format(name,time.ctime()))
time.sleep(1)
lock.release()
def movie(name,loop,lock):
lock.acquire()
for i in range(loop):
print("look movie {} {}".format(name,time.ctime()))
time.sleep(1)
lock.release()
if __name__ == "__main__":
lock = multiprocessing.Lock()
t1 = multiprocessing.Process(target=music, args=("爱转角", 5, lock))
t2 = multiprocessing.Process(target=movie, args=("小王子", 4, lock))
t1.start()
t2.start()
listen music 爱转角 Sat Jul 6 09:09:57 2019
listen music 爱转角 Sat Jul 6 09:09:58 2019
listen music 爱转角 Sat Jul 6 09:09:59 2019
listen music 爱转角 Sat Jul 6 09:10:00 2019
listen music 爱转角 Sat Jul 6 09:10:01 2019
look movie 小王子 Sat Jul 6 09:10:02 2019
look movie 小王子 Sat Jul 6 09:10:03 2019
look movie 小王子 Sat Jul 6 09:10:04 2019
look movie 小王子 Sat Jul 6 09:10:05 2019
多进程池:
Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行它。
进程池方法:
apply(func[, args[, kwds]]): 阻塞的执行,比如创建一个有3个线程的线程池,当执行时是创建完一个,执行完函数再创建另一个,变成一个线性的执行. apply_async(func[, args[, kwds[, callback]]]) : 它是非阻塞执行,同时创建3个线程的线城池,同时执行,只要有一个执行完立刻放回池子待下一个执行,并行的执行 .
close(): 关闭pool,使其不在接受新的任务。
terminate() : 结束工作进程,不在处理未完成的任务。
join(): 主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用。
# 进程池
import multiprocessing
import os
import time
def work1(n):
print("run work {},work id {}".format(n,os.getpid()))
time.sleep(2)
print("work {} stop,work id {}".format(n,os.getpid()))
if __name__ == "__main__":
print("Parent process {}".format(os.getpid()))
p = multiprocessing.Pool(3)
for i in range(10):
p.apply_async(work1,args=(i,))
p.close()
p.join()
Parent process 17352
run work 0,work id 13244
run work 1,work id 4764
run work 2,work id 15784
work 0 stop,work id 13244
run work 3,work id 13244
work 1 stop,work id 4764
run work 4,work id 4764
work 2 stop,work id 15784
run work 5,work id 15784
work 3 stop,work id 13244
run work 6,work id 13244
work 4 stop,work id 4764
run work 7,work id 4764
work 5 stop,work id 15784
run work 8,work id 15784
work 6 stop,work id 13244
run work 9,work id 13244
work 7 stop,work id 4764
work 8 stop,work id 15784
work 9 stop,work id 13244
队列(Queue)
进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列Queue和管道Pipe,这两种方式都是使用消息传递的
创建队列的类(底层就是以管道和锁定的方式实现):
Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
参数介绍:maxsize是队列中允许最大项数,省略则无大小限制
q.put方法用以插入数据到队列中,
put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get方法可以从队列读取并且删除一个元素。
同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
q.get_nowait():同q.get(False)
q.put_nowait():同q.put(False)
q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同上
# 跨进程通信
import multiprocessing
import time
def put_(q):
for value in ['a','b','c']:
print('发送{}到queue。。。'.format(value))
q.put(value)
time.sleep(2)
def get_(q):
while True:
value = q.get(True)
print('从queue接收{}'.format(value))
if __name__ == "__main__":
q = multiprocessing.Queue()
pw = multiprocessing.Process(target=put_,args=(q,))
pr = multiprocessing.Process(target=get_,args=(q,))
# 启动子进程,写入
pw.start()
# 启动子进程pr,读取
pr.start()
pw.join()
#pr 进程是死循环,无法等待其结束;当get无法得到数据时,强制终止
pr.terminate()
发送a到queue。。。
从queue接收a
发送b到queue。。。
从queue接收b
发送c到queue。。。
从queue接收c
管道(pipe):
Pipe方法返回(conn1, conn2)代表一个管道的两个端。Pipe方法有duplex参数:duplex 为 True(默认值),那么这个管道是全双工模式,也就是说conn1和conn2均可收发。duplex 为 False,conn1只负责接受消息,conn2只负责发送消息。
send和recv方法分别是发送和接收消息的方法。在全双工模式下,可以调用conn1.send发送消息,conn1.recv接收消息。如果没有消息可接收,recv方法会一直阻塞。如果管道已经被关闭,那么recv方法会抛出EOFError
# 左边接收,右边发送
import multiprocessing
import time
def send_(q):
for value in ['a','b','c']:
print('发送{}到pipe。。。,{}'.format(value,time.ctime()))
q[1].send(value)
time.sleep(2)
def recv_(q):
while True:
value = q[0].recv()
print('从pipe接收{} {}'.format(value,time.ctime()))
if __name__ == "__main__":
p = multiprocessing.Pipe(duplex=False)
pw = multiprocessing.Process(target=send_,args=(p,))
pr = multiprocessing.Process(target=recv_,args=(p,))
pw.start()
pr.start()
pw.join()
pr.terminate()
发送a到pipe。。。,Sat Jul 6 15:42:44 2019
从pipe接收a Sat Jul 6 15:42:44 2019
发送b到pipe。。。,Sat Jul 6 15:42:46 2019
从pipe接收b Sat Jul 6 15:42:46 2019
发送c到pipe。。。,Sat Jul 6 15:42:48 2019
从pipe接收c Sat Jul 6 15:42:48 2019
生产者消费者:
import threading
import time
import queue
q = queue.Queue(maxsize=10)
def producer(name):
count = 1
while True:
q.put("骨头{}".format(count))
print('生产了骨头{} {}'.format(count,time.ctime()))
count += 1
time.sleep(0.5)
def consumer(name):
while True:
print('{}取到{}并且吃了它。。。。 {}'.format(name,q.get(),time.ctime()))
time.sleep(1)
p = threading.Thread(target=producer,args=("tim",))
c1 = threading.Thread(target=consumer,args=("king",))
c2 = threading.Thread(target=consumer,args=("wang",))
p.start()
c1.start()
c2.start()
生产了骨头1 Sat Jul 6 15:44:29 2019
king取到骨头1并且吃了它。。。。 Sat Jul 6 15:44:29 2019
生产了骨头2 Sat Jul 6 15:44:30 2019
wang取到骨头2并且吃了它。。。。 Sat Jul 6 15:44:30 2019
生产了骨头3 Sat Jul 6 15:44:30 2019
king取到骨头3并且吃了它。。。。 Sat Jul 6 15:44:30 2019
生产了骨头4 Sat Jul 6 15:44:31 2019
wang取到骨头4并且吃了它。。。。 Sat Jul 6 15:44:31 2019
生产了骨头5 Sat Jul 6 15:44:31 2019
king取到骨头5并且吃了它。。。。 Sat Jul 6 15:44:31 2019
生产了骨头6 Sat Jul 6 15:44:32 2019
wang取到骨头6并且吃了它。。。。 Sat Jul 6 15:44:32 2019