python-进程之间通信、多线程介绍
一、进程之间通信
进程的任务有三种状态:运行,就绪,阻塞。
加锁可以让多个进程修改同一块数据时,同一时间只能由一个任务可以进行修改,即串行的修改。牺牲了速度,保证了数据安全。
虽然可以使用文件共享数据实现进程间的通信,但是效率太低,还需要自己加锁处理。为了解决这些问题,便使用到了multiprocessing模块为我们提供的基于消息的IPC通信机制:队列和管道
1.队列和管道都是将数据存放于内存中
2.队列是基于管道+锁的机制实现的。
我们应该尽量避免使用共享数据,多使用队列。
队列:
创建队列的类:
Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
maxsize是队列中允许的最大项数,省略则无大小限制
q = Queue()
q.put() 括号里可以是任意类型,不能是大数据
主要方法:
1 q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。没有参数时,q.put的个数大于队列数时,会一直阻塞住。
2 q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常。没有参数时,q.get的个数大于队列数时,会一直阻塞住。 3.q.put_nowait()等价于q.put(block=False)队列满时再存也会抛异常
q.get_nowait()等价于q.get(block=False)队列为空取不出时会抛异常
from multiprocessing import Queue q=Queue(3) #1.不应该放大数据 2.可以任意类型
q.put(['first',])
q.put({'x':2,})
q.put(3)
# q.put(6)#阻塞在存放的时候,当有内容被取出时才推出阻塞模式 print(q.get())
print(q.get())
print(q.get())
# print(q.get())#阻塞在取的时候,当有新内容添加进去才退出阻塞状态
test
生产者消费者模型:
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。通俗的讲就是当程序中出现明显的两类任务,一类负责生产数据,一类负责处理数据,就可以引入这个模型来实现生产者与消费者的解耦合,平衡生产力与消费能力,从而提升效率。
初级版本:
import time
import random
from multiprocessing import Process,Queue def producer(name,food,q):
for i in range(4):
res = '%s%s'%(food,i)
time.sleep(random.randint(1,3))
q.put(res)
print('厨师[%s]生产了%s'%(name,res)) def consumer(name,q):
while True:
res = q.get()
# if res ==None:break
time.sleep(random.randint(1,3))
print('吃货%s吃了%s'%(name,res)) if __name__ == '__main__':
q = Queue()
#生产者
p1 = Process(target=producer,args=('egon','包子',q))
p2 = Process(target=producer,args=('lxx','豆浆',q))
p3 = Process(target=producer,args=('cw','油条',q))
#消费者
c1 = Process(target=consumer,args=('alex',q))
c2 = Process(target=consumer,args=('yxf',q))
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
print('主')
test1
这个时候就有一个问题,主进程一直在阻塞状态,永远不会结束。这是因为消费者在取空以后 还一直在原地阻塞着。
解决方法:让生产者在生产完毕后再往队列中发送一个结束信号,这样消费者在收到结束信号后跳出循环
版本二:
import time
import random
from multiprocessing import Process,Queue def producer(name,food,q):
for i in range(4):
res = '%s%s'%(food,i)
time.sleep(random.randint(1,3))
q.put(res)
print('厨师[%s]生产了%s'%(name,res)) def consumer(name,q):
while True:
res = q.get()
if res ==None:break
time.sleep(random.randint(1,3))
print('吃货%s吃了%s'%(name,res)) if __name__ == '__main__':
q = Queue()
#生产者
p1 = Process(target=producer,args=('egon','包子',q))
p2 = Process(target=producer,args=('lxx','豆浆',q))
p3 = Process(target=producer,args=('cw','油条',q))
#消费者
c1 = Process(target=consumer,args=('alex',q))
c2 = Process(target=consumer,args=('yxf',q)) p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
p1.join()
p2.join()
p3.join()
q.put(None)
q.put(None)
q.put(None)
print('主')
test2
但是有几个生产者我们就要发送几个None,这不够优雅,于是我们导入了JoinableQueue模块
#JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。 #参数介绍:
maxsize是队列中允许最大项数,省略则无大小限制。
#方法介绍:
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
版本三:
import time
import random
from multiprocessing import Process,JoinableQueue def producer(name,food,q):
for i in range(4):
res = '%s%s'%(food,i)
time.sleep(random.randint(1,3))
q.put(res)
print('厨师[%s]生产了%s'%(name,res)) def consumer(name,q):
while True:
res = q.get()
time.sleep(random.randint(1,3))
print('吃货%s吃了%s'%(name,res))
q.task_done() if __name__ == '__main__':
q = JoinableQueue() #生产者
p1 = Process(target=producer,args=('egon','包子',q))
p2 = Process(target=producer,args=('lxx','豆浆',q))
p3 = Process(target=producer,args=('cw','油条',q))
#消费者
c1 = Process(target=consumer,args=('alex',q))
c2 = Process(target=consumer,args=('yxf',q))
c1.daemon=True
c2.daemon=True p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
p1.join()
p2.join()
p3.join() q.join()#主进程等q结束,即q内数据被取干净了。
print('主')
二、线程理论
进程是资源单位,由若干线程组成的,一个进程至少有一个线程,线程是操作系统直接支持的执行单元。一个进程相当于一块空间,空间内有若干的线程,就好比进程是一个车间,线程就是车间的流水线。同一个进程之间的线程是资源共享的。进程是程序执行的过程,那么线程就是程序执行的代码。
线程相比进程的优点:1.同一进程下,多个线程共享进程内的资源
2.创建线程的开销远远小于进程
三、线程的使用
(一).创建线程的两种方式(和进程类似)
from threading import Thread
import time def task(name):
print('%s is running'%name)
time.sleep(2)
print('%s is done'%name) if __name__ == '__main__':
t = Thread(target=task,args=('进程一',))
t.start()
print('主')
方式一
直接导入threading模块
from threading import Thread
import time class Mythead(Thread):
def __init__(self,name):
super().__init__()
self.name = name def run(self):
print('%s is running' % self.name)
time.sleep(0.1)
print('%s is done' % self.name) if __name__ == '__main__':
t = Mythead('线程一')
t.start()
print('主')
方式二
继承Therad类重写run方法
(二).线程特性介绍
os模块下的getpid()线程也适用
current_thread#查看当前线程
active_count#查看线程的活跃个数(线程已结束的不是活跃状态)
current_thread().name查看线程名字
略
(三).守护线程
无论是进程还是线程都遵循 某线程/进程等待 主线程/进程 运行完毕后才会被销毁。强调:运行完毕并非终止运行
#1.对主进程来说,运行完毕指的是主进程代码运行完毕。
主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束, #2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕。
主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
from threading import Thread
from multiprocessing import Process
import time
def foo():
print(123)
time.sleep(1)
print("end123") def bar():
print(456)
time.sleep(3)
print("end456") if __name__ == '__main__':
t1=Thread(target=foo)
t2=Thread(target=bar) # t1=Process(target=foo)
# t2=Process(target=bar)
t1.daemon=True
t1.start()
t2.start()
print("main-------")
进程与线程的区别
(四).线程的互斥锁
不加锁的情况
from threading import Thread,Lock
import time mutex=Lock()
n=100
def task():
global n
# mutex.acquire()
temp=n
time.sleep(0.1)
n=temp-1
# mutex.release() if __name__ == '__main__':
t_l=[]
for i in range(100):
t=Thread(target=task)
t_l.append(t)
t.start() for t in t_l:
t.join()
print(n)
结果永远为99,因为线程速度太快了,并发的时候都读到了n=100,所以需要给他加上锁
加上锁的情况
from threading import Thread,Lock
import time mutex=Lock()
n=100
def task():
global n
mutex.acquire()
temp=n
time.sleep(0.1)
n=temp-1
mutex.release() if __name__ == '__main__':
t_l=[]
for i in range(100):
t=Thread(target=task)
t_l.append(t)
t.start() for t in t_l:
t.join()
print(n)
python-进程之间通信、多线程介绍的更多相关文章
- Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型
Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型 一丶互斥锁 含义: 每个对象都对应于一个可称为" 互斥锁&qu ...
- python进程之间的通信——Queue
我们知道进程之间的数据是互不影响的,但有时我们需要在进程之间通信,那怎么办呢? 认识Queue 可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息 ...
- Python 进程之间共享数据
最近遇到多进程共享数据的问题,到网上查了有几篇博客写的蛮好的,记录下来方便以后查看. 一.Python multiprocessing 跨进程对象共享 在mp库当中,跨进程对象共享有三种方式,第一种 ...
- 【linux】mkfifo 命令创建命名管道实现进程之间通信
mkfifo 命令 mkfifo命令创建一个FIFO特殊文件,是一个命名管道(可以用来做进程之间通信的桥梁) 管道也是一种文件,一般是linux中的一个页大小,4k,管道数据一旦被读取就没了.(管道大 ...
- 进程与进程之间通信Manager
#!/usr/bin/env python from multiprocessing import Process,Manager #Manager进程与进程之间通信 def Foo(i,dic): ...
- python 进程之间的通讯
python 进程之间的通讯 #!/usr/bin/env python #-*- coding:utf-8 -*- # author:leo # datetime:2019/5/28 10:15 # ...
- IPC进程之间通信的几种方式
概念 进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是 共享内存区 .但是,系统空间却是 ...
- Python 进程之间共享数据(全局变量)
进程之间共享数据(数值型): import multiprocessing def func(num): num.value=10.78 #子进程改变数值的值,主进程跟着改变 if __name__= ...
- python进程之间修改数据[Manager]与进程池[Pool]
#前面的队列Queue和管道Pipe都是仅仅能再进程之间传递数据,但是不能修改数据,今天我们学习的东西就可以在进程之间同时修改一份数据 #Mnager就可以实现 import multiprocess ...
- 跨进程(同一app不同进程之间通信)——Android自动化测试学习历程
视频地址:http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=877122&co ...
随机推荐
- linux上安装mysql,tomcat,jdk
Linux 上安装 1 安装jdk 检测是否安装了jdk 运行 java –version 若有 需要将其卸载 a) 查看安装哪些jdk rmp –qa |grep java b) ...
- 复习java web之jsp入门_El表达式_JSTL标签库
JSP 技术掌握:JSP语法 + EL + JSTL 为什么sun推出 JSP技术 ? Servlet 生成网页比较复杂,本身不支持HTML语法,html代码需要通过response输出流输出,JSP ...
- JDK自带的LinkedHashMap来实现LRU算法
1 代码如下 public class LRULinkedHashMap<K, V> extends LinkedHashMap<K, V> { private final i ...
- java实现打印前台页面
核心:用window自带方法 window.print(); 打印的范围:body里内容,只要在页面能显示出来,都打印 遇到的问题:打印按钮被一起打印出来了,url也别打印出来了 解决办法:在触发打印 ...
- bae64编码
data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAYAAABIdFAMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJb ...
- RocketMQ RPC
(1)NameServer:在MQ集群中做的是做命名服务,更新和路由发现 broker服务: (2)Broker-Master:broker 消息主机服务器: (3)Broker-Slave:brok ...
- mysql 原理~ FTWRDL
FTWRL 锁与MDL一 简介:今天来聊聊为什么备份会卡住,申请不到全局FTWRL二 FTWRL 1 FTWRL主要包括3个步骤: 1.上全局读锁(lock_global_read_lo ...
- Flask恋爱的一瞬间
python的三大框架:Flask:轻量级框架 Django:重量级框架 Tornado:性能最好,异步框架 Flask初学 #导包 from flask import Flask #建立flask对 ...
- 音乐app各部分笔记(二)
7-15播放器progress-circle圆形进度条组件实现 1.首先是引入三步 progress-circle 引入到player.vue中 然后就是 SVG技术 值得注意的事 svg 中 ...
- Javascript - ExtJs - Itemselector
引入扩展文件 Extjs4.2根目录下: examples \ ux \ css \ images (这是选择按钮的图片资源) examples \ ux \ css \ ItemSelector.c ...