一、进程之间通信

进程的任务有三种状态:运行,就绪,阻塞。

加锁可以让多个进程修改同一块数据时,同一时间只能由一个任务可以进行修改,即串行的修改。牺牲了速度,保证了数据安全。

虽然可以使用文件共享数据实现进程间的通信,但是效率太低,还需要自己加锁处理。为了解决这些问题,便使用到了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-进程之间通信、多线程介绍的更多相关文章

  1. Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型

    Python进阶----进程之间通信(互斥锁,队列(参数:timeout和block),), ***生产消费者模型 一丶互斥锁 含义: ​ ​ ​ 每个对象都对应于一个可称为" 互斥锁&qu ...

  2. python进程之间的通信——Queue

    我们知道进程之间的数据是互不影响的,但有时我们需要在进程之间通信,那怎么办呢? 认识Queue 可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息 ...

  3. Python 进程之间共享数据

    最近遇到多进程共享数据的问题,到网上查了有几篇博客写的蛮好的,记录下来方便以后查看. 一.Python multiprocessing 跨进程对象共享  在mp库当中,跨进程对象共享有三种方式,第一种 ...

  4. 【linux】mkfifo 命令创建命名管道实现进程之间通信

    mkfifo 命令 mkfifo命令创建一个FIFO特殊文件,是一个命名管道(可以用来做进程之间通信的桥梁) 管道也是一种文件,一般是linux中的一个页大小,4k,管道数据一旦被读取就没了.(管道大 ...

  5. 进程与进程之间通信Manager

    #!/usr/bin/env python from multiprocessing import Process,Manager #Manager进程与进程之间通信 def Foo(i,dic): ...

  6. python 进程之间的通讯

    python 进程之间的通讯 #!/usr/bin/env python #-*- coding:utf-8 -*- # author:leo # datetime:2019/5/28 10:15 # ...

  7. IPC进程之间通信的几种方式

    概念 进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是 共享内存区 .但是,系统空间却是 ...

  8. Python 进程之间共享数据(全局变量)

    进程之间共享数据(数值型): import multiprocessing def func(num): num.value=10.78 #子进程改变数值的值,主进程跟着改变 if __name__= ...

  9. python进程之间修改数据[Manager]与进程池[Pool]

    #前面的队列Queue和管道Pipe都是仅仅能再进程之间传递数据,但是不能修改数据,今天我们学习的东西就可以在进程之间同时修改一份数据 #Mnager就可以实现 import multiprocess ...

  10. 跨进程(同一app不同进程之间通信)——Android自动化测试学习历程

    视频地址:http://study.163.com/course/courseLearn.htm?courseId=712011#/learn/video?lessonId=877122&co ...

随机推荐

  1. springboot(十六):springboot整合shiro

    数据库有五张表(userInfo,uerrole,role,rolepermission,permission) userInfo(id,username,password) userrole(uid ...

  2. luogu 2048 超级钢琴 贪心+堆+RMQ

    此题求长度在l,r,之间内的区间的前k大之和 1.静态区间第k大,不就是主席树么! 可是不会写啊,以后填坑吧 2.优先队列 固定左端点,选取以此为起点的长度l<=x<=r的区间,固定此范围 ...

  3. 最好用的js前端框架、组件、文档在线预览插件

    这里收集的都是个人认为比较好的js框架.组件 js前端ui框架 此处列举出个人认为最好的几个框架(排序即排名),现在好点的框架商用都需要付费,以下几个也不例外,但是由于组件丰富,都可以作为企业应用的完 ...

  4. hasnMap的基本操作 源码(三)

    一.初始化: hashMap有四种初始化方式: public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity ...

  5. Docker 随 docker服务重启

     在创建时添加 重启 docker run --restart=always -d --name web -p : -v /data/web:/usr/local/tomcat/webapps tom ...

  6. 昨天看了一个大神的fix类,清晰了然

    .fix::after{ content:''; display:table; clear:both; }

  7. vue 学习笔记—Es6

    // 第一部分 /* console.log(a+'c'); var a = 1; console.log(b+'c'); let b =1; */ // 上述代码 left定义报错 原因: /* v ...

  8. tkinter模块常用参数python

    1.使用tkinter.Tk()生成主窗口(root = tkinter.Tk()) root.title("标题名")       修改窗体的名字,也可以在创建的时候使用clas ...

  9. python第l六天,lambda表达式学习,涉及filter及Map。

    在python中lambda表达式可以作为匿名函数来使用,举一个简单的栗子: 以前我们写两个数相加的函数需要 #以前我们写两个数相加的函数,需要这样写 >>> def sum(x,y ...

  10. kali linux 安装virtualbox报错(rc=-1908)

    解决步骤: apt-get install dkms # 如何安装了dkms就跳过这步 apt-get install linux-headers-`uname -r` # 这个符号是TAB上方的符号 ...