线程
进程间通信
IPC机制
进程之间存在内存的物理隔离,数据不共享,所以需要有能存放公共数据的地方
1.管道
import subprocess
subprocess.Popen('dir',
shell=True,
stdout=subprocess.PIPE, #把数据存入管道中
stderr=subprocess.PIPE)
2.队列 (等于管道+锁)
from multiprocessing import Queue
q=Queue(3)#创建队列对象,并且只能存放3个数据
q.put(obj) #往队列中添加数据
q.put(obj)
q.put_nowait(obj)#添加数据,无等待,满了直接报错,这里没有满,不会报错,其实就等同于q.put(block=False)
print(q.full()) #如果已经满的话,输出True,否则为False
q.put(obj,block=True,timeout=1)#等待一秒,如果数据仍然是满的,没有被取出,就直接报错(没有timeout默认一直等待)
q.get()#在队列中取数据
q.get()
q.get_nowait()#无等待取出数据,没有数据直接报错empty,等同于q.get(block=False)
print(q.empty())#如果已经空的话,输出True,否则为False
q.get(obj,block=True,timeout=1)#等待一秒,如果数据仍然是空的,就直接报错(没有timeout默认一直等待)
生产者消费者模型
解决供需不平衡的问题
定义一个队列,用来存放固定数量的数据
让一个生产者和消费者不直接打交道,解耦合
1.例子(在生产者运行结束后,队列添加None,当取到None的时候结束等待终止循环,让主进程正常结束)
from multiprocessing import Process,Queue
import time
import random
def producer(name,food,q):
for i in range(5):
data='%s%s'%(food,i)
time.sleep(random.randint(1,3))#模拟制作时间,1到3秒不等
print('%s制作了%s'%(name,data))
q.put(data)
def customer(name,q):
while 1:
mes=q.get() #如果没有收到数据,会一直等待,所以才有下面的if
if mes==None:break #当收到None的时候,停止循环,让主进程正常退出
time.sleep(random.randint(1,3))#模拟进食时间
print('%s吃了%s'%(name,mes))
if __name__=='__main__':
q=Queue() #生成一个队列对象,用来给消费者和生产者搭桥
p=Process(target=producer,args=('大厨','牛排',q))#生成一个生产者进程
c=Process(target=customer,args=('我',q))#生成一个消费进程
p.start()
c.start()
p.join()#确保在生产者结束
q.put(None)#确保在生产者结束后,给列表添加None
2.方法二(利用守护进程,确保生产者结束后,列表中没有数据的时候,消费者进程随着主进程结束而结束)
from multiprocessing import Process,JoinableQueue
import time
import random
def producer(name,food,q):
for i in range(5):
data='%s%s'%(food,i)
time.sleep(random.randint(1,3))#模拟制作时间,1到3秒不等
print('%s制作了%s'%(name,data))
q.put(data)
def customer(name,q):
while 1:
mes=q.get()
time.sleep(random.randint(1,3))#模拟进食时间
print('%s吃了%s'%(name,mes))
q.task_done()#告诉队列数据已经取出,且已经处理完毕
if __name__=='__main__':
q=JoinableQueue() #生成一个队列对象,用来给消费者和生产者搭桥
p=Process(target=producer,args=('大厨','牛排',q))#生成一个生产者进程
c=Process(target=customer,args=('我',q))#生成一个消费进程
c.daemon=True #把消费者做成守卫进程,随着主进程一起结束
p.start()
c.start()
p.join()#确保在生产者结束
q.join()#确保数据已经全部取出
线程理论
进程:资源单位
线程:执行单位(执行的最小单位)
每一个进程中都会自带一个线程
为什么要有线程
开一个进程
申请内存空间 耗时
将代码拷贝到申请的内存空间中 耗时
开线程
不需要申请内存空间
开线程的消耗远远小于开进程的开销!!(时间约100倍)
开线程的两种方式
方式一
from threading import Thread
import time
def task(name):
print('%s is running'%name)
time.sleep(1)
print('%s is over'%name)
if __name__ == '__main__':
t = Thread(target=task,args=('egon',))
t.start() # 开启线程的速度非常快,几乎代码执行完线程就已经开启
print('主')
方式二
from threading import Thread
import time
class MyThread(Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
print('%s is running' % self.name)
time.sleep(1)
print('%s is over'%self.name)
if __name__ == '__main__':
t = MyThread('jason')
t.start()
print('主')
线程之间数据共享的
from threading import Thread
x = 100
def task():
global x
x = 666
t = Thread(target=task)
t.start()
t.join()#确保子进程先运行
print(x)
#输出为666,说明资源是共享的,MAYBE='其实就是访问全局的变量,子线程中(局部)可以访问主线程(全局),但是主线程不能访问子线程'?
线程互斥锁
from threading import Thread,Lock
import time
import random
mutex = Lock()
n = 100
def task():
global n
mutex.acquire()
tmp = n
time.sleep(0.1)
n = tmp -1
mutex.release()
t_list = []
for i in range(100):
t = Thread(target=task)
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(n)
线程对象的其他属性和方法
from threading import Thread,active_count,current_thread
import os
import time
def task(name):
# print('%s is running'%name,os.getpid())
print('%s is running'%name,current_thread().name,current_thread().getName())
time.sleep(1)
print('%s is over'%name)
def info(name):
print('%s is running' % name, current_thread().name, current_thread().getName())
time.sleep(1)
print('%s is over' % name)
t = Thread(target=task,args=('关磊',),name='线程')
t1 = Thread(target=info,args=('关超',))
t.start()
t1.start()
t.join()
print(active_count()) # 当前存活的线程数
print(os.getpid()) #得到pid,进程的pid,同一进程中都相同
print(current_thread().name)
print(current_thread().getName()) #得到线程名字,没有采用默认
守护线程
from threading import Thread
import time
def task(name):
print('%s is running'%name)
time.sleep(1)
print('%s is over'%name)
if __name__ == '__main__':
t = Thread(target=task,args=('王磊',))
t.daemon = True
t.start()
print('主')