一、进程之间通信

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

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

虽然可以使用文件共享数据实现进程间的通信,但是效率太低,还需要自己加锁处理。为了解决这些问题,便使用到了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. JS 数组中对象去重 reduce 用法

    对于数组对象,传统的去重方法无能为力,至于forEach().filter()等迭代方法也不好使:真正能做到优雅去重的,是ES5新增加的一个方法——reduce() 高手给的,完美方法 let log ...

  2. C# Math.Round实现中国式四舍五入

    decimal sum = 11111.334; sum = , MidpointRounding.AwayFromZero);  sum:11111.33decimal sum = 11111.34 ...

  3. termios结构体的内容

    一.结构体成员 struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; cc_ ...

  4. 传入mybatis的xml为Long型时报There is no getter for property named 'VARCHAR' in

    修改前   <insert id="insert" parameterType="com.taotao.pojo.TbContent" >    i ...

  5. PDO和MySQLi区别与选择?

    当用PHP访问数据库时,除了PHP自带的数据库驱动,我们一般还有两种比较好的选择:PDO和MySQLi.在实际开发过程中要决定选择哪一种首先要对二者有一个比较全面的了解.本文就针对他们的不同点进行分析 ...

  6. Mysql 基础导入导出

    Mysql 导出数据库: mysqldump -u root -p 数据库 > 导出库名.sql mysqldump -u 用户名 -p 数据库名 表名 > 导出表名.sql 示例:mys ...

  7. scrapy和scrapy_redis入门

    Scarp框架 需求 获取网页的url 下载网页内容(Downloader下载器) 定位元素位置, 获取特定的信息(Spiders 蜘蛛) 存储信息(ItemPipeline, 一条一条从管里走) 队 ...

  8. python3:实现输出等边三角形、直角三角形

    学习python,用的是3.5的版本: 记录一下学习历程~ 一.先来一个简单的,输出直角三角形: ***知识点:for循环,range()函数 二.进阶:输出等边三角形 ******知识点:嵌套for ...

  9. vue通俗易懂的子组件向父组件传值

    不多BB直接上图: 如上图:为子组件绑定点击事件 如上图:send方法触发父组件绑定的事件 如上图:为父组件绑定触发事件@myEvent="aa" aa方法接受子组件传过来的值

  10. java包装类型的坑

    开发中有遇到Long类型比较是否相等,比如Long A和Long B判断是否相等,当时习惯性的直接A==B: 自测的话确实么有问题,但是测试那边测试就有问题,当时郁闷了一下然后换成了A.equals( ...