python 进程间通信_Python 进程间通信 线程

一 进程间通信(IPC)

IPC

进程之间相互隔离,当一个进程想要把数据给另一个进程,就要考虑IPC(进程间通信)

进程间通信的方式:

1. 管道:只能单向通讯,数据都是二进制

2. 文件:在硬盘上创建共享文件,

缺点:速度快

优点:数据量几乎没有限制

3. socket:编程复杂度较高

4. 共享内存:必须要操作系统来分配

优点:速度快

缺点:数据量不能太大

1.manger类 了解

需要强调的是 Manager创建的一些数据结构是不带锁的 可能会出现问题

Manager提供很多数据结构 list dict等等

Manager所创建出来的数据结构,具备进程间共享的特点from multiprocessing importProcess,Manager,Lockimporttimedeftask(data,l):

l.acquire()

num= data["num"] # time.sleep(0.1)

data["num"] = num - 1l.release()if __name__ == '__main__':#让Manager开启一个共享的字典

m =Manager()

data= m.dict({"num":10})

l=Lock()for i in range(10):

p= Process(target=task,args=(data,l))

p.start()

time.sleep(2)print(data)

View Code

2.Queue队列

队列:先进先出

堆栈:先进后出

队列是一种特殊的数据结构,先存储的先取出 就像排队 先进先出

​相反的是堆栈,先存储的后取出, 就像衣柜 桶装薯片 先进后出

​扩展:

​ 函数嵌套调用时 执行顺序是先进后出 也称之为函数栈

​ 调用 函数时 函数入栈 函数结束就出栈from multiprocessing importQueue#创建队列对象 不指定maxsize 则没有数量限制

q = Queue(3)#存放值

q.put(1)

q.put(2)

q.put(3)#print(q.full()) # 判断队列是否满了 True#q.put(4) # 如果容量已经满了,在调用put时将进入阻塞状态 直到有人从队列中拿走数据有空位置 才会继续执行

#取值

print(q.get()) #1

print(q.get()) #2

print(q.get()) #3

print(q.empty()) #判断队列中的数据是否取完 True#print(q.get())# 如果队列已经空了,在调用get时将进入阻塞状态 直到有人从存储了新的数据到队列中 才会继续#print(q.get_nowait()) # 取值 没有值不等待直接报错

补充:#block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列为空时 抛出异常

q.get(block=True,timeout=2)#block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列满了时 抛出异常#q.put("123",block=False,)#timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常 仅在block为True有效

"""full

get_nowait

empty

都不适用于多进程的情况"""

View Code

from multiprocessing importProcess,Queuedefproducer(q):

q.put('hello GF~')defconsumer(q):print(q.get())if __name__ == '__main__':

q=Queue()

p= Process(target=producer,args=(q,))

c= Process(target=consumer, args=(q,))

p.start()

c.start()"""子进程放数据 主进程获取数据

两个子进程相互放 取数据"""

View Code

3.生产者和消费者

1.生产者:产生数据的一方称之为生产者。

消费者:处理数据的一方称之为消费者

2.问题:生产者和消费,处理速度不平衡,一方快一方慢,导致一方需要等待另一方。

3.解决方法:

将双方分开来.一专门负责生成,一方专门负责处理

这样一来数据就不能直接交互了 双方需要一个共同的容器

生产者完成后放入容器,消费者从容器中取出数据

这样就解决了双发能力不平衡的问题,做的快的一方可以继续做,不需要等待另一方

defeat(q):for i in range(10):#要消费

rose =q.get()

time.sleep(random.randint(0,2))print(rose,"吃完了!")#生产任务

defmake_rose(q):for i in range(10):#再生产

time.sleep(random.randint(0, 2))print("第%s盘青椒肉丝制作完成!" %i)

rose= "第%s盘青椒肉丝" %i#将生成完成的数据放入队列中

q.put(rose)if __name__ == '__main__':#创建一个共享队列

q =Queue()

make_p= Process(target=make_rose,args=(q,))

eat_p= Process(target=eat,args=(q,))

make_p.start()

eat_p.start()

View Code

4.JoinableQueue

1.生产者和消费者问题:

生产者生产结束以后,消费者一直循环吃,吃完以后,消费者并不知道

生产者已经生产结束,就会一直等待生产者生产东西

2.解决方法:JoinableQueue

例1:from multiprocessing importJoinableQueue#可以被join的队列,join是等待摸个任务完成,able 可以怎么着, Queue是队列

from multiprocessing importProcess,Queue,JoinableQueueimportrandomimporttimedefproducer(name,food,q):for i in range(10):

data= '%s生产了%s%s'%(name,food,i)

time.sleep(random.random())

q.put(data)print(data)defconsumer(name,q):whileTrue:

data=q.get()if data == None:break

print('%s吃了%s'%(name,data))

time.sleep(random.random())

q.task_done()#告诉队列你已经从队列中取出了一个数据 并且处理完毕了,task_down的次数 == get的次数,一次get对应一个taskdone连起来用

if __name__ == '__main__':

q=JoinableQueue()

p= Process(target=producer,args=('大厨egon','馒头',q))

p1= Process(target=producer,args=('跟班tank','生蚝',q))

c= Process(target=consumer,args=('许兆龙',q))

c1= Process(target=consumer,args=('吃货jerry',q))

p.start()

p1.start()

c.daemon=True

c1.daemon=True

c.start()

c1.start()

p.join()

p1.join()

q.join()#阻塞等到队列中数据全部取出

print('主')

例2:from multiprocessing importJoinableQueue#可以被join的队列,join是等待摸个任务完成,able 可以怎么着, Queue是对垒

q=JoinableQueue()

q.put("1")

q.put("2")print("取走了一个%s" %q.get())

q.task_done()#task_down 告诉队列这个数据已经处理完了#该函数不是表示任务全部处理完成,而是取出某个数据处理完成

print("再取走了%s" %q.get())

q.task_done()print("......")#q.join() #等待队列中的数据处理完毕 , join, task_down的次数 == put的次数

print("Game Over")

View Code

二 线程

1.线程基础

1.什么线程:线程是操作系统运算调度的最小单位 (CPU最小执行单位),进程好比是一个车间(资源单位)线程就是车间的流水线(执行单位)。

2.线程和进程的区别:

1.线程创建的开销远小于进程

2.统一进程中的所有线程共享进程内的资源

3.线程之间没有父子关系,都是平等的,PID相同

3.线程特点:

1.每个进程都会有一个默认的线程

2.每个进程可以存在多个线程

3.同一进程中的所有线程之间数据是共享的

4.创建线程的开销远比创建进程小的多

如何选择:

要根据具体的任务类型,IO密集 计算密集

4.开启线程的两种方式

1.实例化Tread类,target参数用于指定子线程要执行的任务from threading importThreaddeftask():print("子线程 run........")

t= Thread(target=task)

t.start()print("over")2.继承Tread类,覆盖run方法classMyThread(Thread):def __init__(self,name):

super().__init__()

self.name=namedefrun(self):print('%s is running'%self.name)

time.sleep(3)print('%s is over'%self.name)

t= MyThread('egon')

t.start()print('主')**与进程在使用方法上没有任何区别,不同的是开启子线程的代码可以写在任意位置**之所以使用方法完全相同是因为,多进程其实是为了弥补多线程的缺憾而诞生的。详见GIL锁

View Code

2.Tread类的常用属性:

#threading模块包含的常用方法

importthreadingprint(threading.current_thread().name) #获取当前线程对象

print(threading.active_count()) #获取目前活跃的线程数量

print(threading.enumerate()) #获取所有线程对象

t= Thread(name="aaa")#t.join() # 主线程等待子线程执行完毕

print(t.name) #线程名称

print(t.is_alive()) #是否存活

print(t.isDaemon()) #是否为守护线程

from threading importThread,current_thread,active_countimporttimeimportosdeftask(name,i):print('%s is running'%name)#print('子current_thread:',current_thread().name)

#print('子',os.getpid())

time.sleep(i)print('%s is over'%name)#开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内

t = Thread(target=task,args=('egon',1))

t1= Thread(target=task,args=('jason',2))

t.start()#告诉操作系统开辟一个线程 线程的开销远远小于进程

t1.start() #告诉操作系统开辟一个线程 线程的开销远远小于进程

t1.join() #主线程等待子线程运行完毕

print('当前正在活跃的线程数',active_count())#小的代码执行完 线程就已经开启了

print('主')#print('主current_thread:',current_thread().name)#print('主',os.getpid())

View Code

3.守护线程

设置守护线程的语法与进程相同,相同的是也必须放在线程开启前设置,否则抛出异常。

守护线程的特点:1.守护线程会在被守护线程结束后立即结束,2.主线程的结束也就意味着进程的结束

主线程必须等待其他非守护线程的结束才能结束

(意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)

换句话说,守护线程会在所有非守护线程执行完毕后结束。from threading importThreadimporttimedeftask():print("start....1")

time.sleep(3)print("end......1")deftask2():print("start....2")

time.sleep(4)print("end......2")

t= Thread(target=task)

t.daemon=True

t.start()

t2= Thread(target=task2)

t2.start()print("main over!")

View Code

4.线程间通信

from threading importThread

money= 666

deftask():globalmoney

money= 999t= Thread(target=task)

t.start()

t.join()print(money) #999

#同一进程下的线程间数据是共享的

View Code

5.互斥锁

from threading importThread,Lockimporttime

n= 100

deftask(mutex):globaln

mutex.acquire()

tmp=n

time.sleep(0.1)

n= tmp - 1mutex.release()

t_list=[]

mutex=Lock()for i in range(100):

t= Thread(target=task,args=(mutex,))

t.start()

t_list.append(t)for t int_list:

t.join()print(n) #0

View Code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值