多进程(了解),守护进程,互斥锁,信号量,进程Queue与线程queue

一、守护进程

  主进程创建守护进程,守护进程的主要的特征为:①守护进程会在主进程代码执行结束时立即终止;②守护进程内无法继续再开子进程,否则会抛出异常。

实例:

from multiprocessing import Process
from threading import Thread
import time
def foo():  # 守护进程
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == ‘__main__‘:

    p1=Process(target=foo)
    p2=Process(target=bar)

    p1.daemon=True
    p1.start()
    p2.start()
    print("main-------") #打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止

  注:打印最后一行主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息‘start123’,因为主进程打印main-时,p1也执行了,但是随即被终止。

from threading import Thread
import time
def foo():  # 守护线程
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")

if __name__ == ‘__main__‘:
    p1=Thread(target=foo)
    p2=Thread(target=bar)

    p1.daemon=True
    p1.start()
    p2.start()
    print("main-------")
# 123
# 456
# main-------
# end123
# end456

守护线程

from threading import Thread
import time
def foo():
    print(123)
    time.sleep(5)
    print(‘end123‘)
def bar():
    print(‘start456‘)
    time.sleep(3)
    print(‘end456‘)
if __name__ == ‘__main__‘:
    t1=Thread(target=foo)
    t2=Thread(target=bar)
    t1.daemon=True  #必须放在start()前
    t1.start()
    t2.start()
    print(‘main‘)

# 123
# start456
# main
# end456

与上比较

二、互斥锁 

  进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,竞争带来的结果就是错乱,如何控制,就是加锁处理(即局部实行串行)。

模拟抢票实例:

from multiprocessing import Process,Lock
import json,os,time,random

def search():
    with open(‘db.txt‘,encoding=‘utf-8‘)as f:
        dict = json.load(f)
        print(‘%s 剩余票数 %s‘%(os.getpid(),dict[‘count‘]))

def get():
    with open(‘db.txt‘,encoding=‘utf-8‘) as reaf_f:
        dic = json.load(reaf_f)

    if dic[‘count‘]>0:
        dic[‘count‘] -= 1
        time.sleep(random.randint(1,3))  # 模拟手速,网速
        with open(‘db.txt‘,‘w‘,encoding=‘utf-8‘) as write_f:
            json.dump(dic,write_f)
            print(‘%s 抢票成功‘ %os.getpid())
    else:
        print(‘剩余票数为%s,购票失败‘%dic[‘count‘])

def task(mutex):
    search()    # 20个人都可以并发的查询票数
    mutex.acquire()    # 加锁
    get()              #通过锁,查询到结果的20人通过竞争逐一买票。前一个释放锁后后一个才可以进入,即串行
    mutex.release()    # 解锁

if __name__ == ‘__main__‘:
    mutex = Lock()
    for i in range(20):  # 20个人抢票
        p = Process(target=task,args=(mutex,))
        p.start()

三、信号量

同进程的一样

Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。

实例:(同时只有5个线程可以获得semaphore,即可以限制最大连接数为5):

from multiprocessing import Process,Semaphore
# from threading import Thread,Semaphore
import time,random,os

def task(sm):
    with sm:
        print(‘%s 上厕所‘ %os.getpid())
        time.sleep(random.randint(1,3))

if __name__ == ‘__main__‘:
    sm = Semaphore(3)
    for i in range(10):
        p= Process(target=task,args=(sm,))
        p.start()

与进程池是完全不同的概念,进程池Pool(4),最大只能产生4个进程,而且从头到尾都只是这四个进程,不会产生新的,而信号量是产生一堆线程/进程

四、进程间通信机制(IPC)

  基于互斥锁以上两种缺点,multiprocessing模块为我们提供了基于消息通信IPC机制:队列和管道。队列和管道都是将数据存放于内存中;队列又是基于(管道+锁)实现的,可以让我们从复杂的锁问题中解脱出来,我们应该尽量避免使用共享数据,尽可能使用消息传递和队列,避免处理复杂的同步和锁问题,而且在进程数目增多时,往往可以获得更好的可获展性。

1、队列(推荐)

(1)队列相关知识

  队列创建介绍:

from multiprocessing import Queue      #引入Queue类
q=Queue(n)              #实例化,参数n代表队列中最大允许存放数,省略则无限制

  常见使用方法:

q.put()                 #用于插入数据到队列
q.get()                 #用于从队列读取并删除一个数据
q.put_nowait()          #当队列存在数据已超过最大限制数,则抛出Queue.full异常
q.get_nowait()          #当队列中已经不存在可取数据时,则抛出Queue.empty异常

  例子:

from multiprocessing import Queue
q=Queue(3)
q.put({‘a‘:1})
q.put(‘bbbb‘)
q.put((3,2,1))
# q.put_nowait(1111111)  #queue.Full

print(q.get())
print(q.get())
print(q.get())
# print(q.get_nowait())  #queue.Empty

(2)生产消费者模型

  生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

  实例1:

from multiprocessing import Process,Queue
import time,random,os

def procducer(q):
    for i in range(10):
        res=‘包子%s‘ %i
        time.sleep(0.5)
        q.put(res)
        print(‘%s 生产了 %s‘ %(os.getpid(),res))

def consumer(q):
    while True:
        res=q.get()
        if res is None:
            break
        print(‘%s 吃 %s‘ %(os.getpid(),res))
        time.sleep(random.randint(2,3))

if __name__ == ‘__main__‘:
    q=Queue()
    p=Process(target=procducer,args=(q,))
    c=Process(target=consumer,args=(q,))

    p.start()
    c.start()
    print(‘主‘)

此时的问题是主进程永远不会结束,原因是:生产者p在生产完后就结束了,但是消费者c在取空了q之后,则一直处于死循环中且卡在q.get()这一步。解决方式无非是让生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死循环。

  例子2:

from multiprocessing import Process,Queue
import time,random,os

def procducer(q):
    for i in range(10):
        res=‘包子%s‘ %i
        time.sleep(0.5)
        q.put(res)
        print(‘%s 生产了 %s‘ %(os.getpid(),res))

def consumer(q):
    while True:
        res=q.get()
        if res is None:
            break
        print(‘%s 吃 %s‘ %(os.getpid(),res))
        time.sleep(random.randint(2,3))

if __name__ == ‘__main__‘:
    q=Queue()
    p=Process(target=procducer,args=(q,))
    c=Process(target=consumer,args=(q,))

    p.start()
    c.start()

    p.join()
    q.put(None)
    print(‘主‘)

注意:以上发送可以放在生产函数中循环完进行发送,当然也可以如上放在主进程中进行发送,但是前提是必须等生产子进程结束才可以。

时间: 2024-10-12 15:22:41

多进程(了解),守护进程,互斥锁,信号量,进程Queue与线程queue的相关文章

开启子进程的两种方式,孤儿进程与僵尸进程,守护进程,互斥锁,IPC机制,生产者与消费者模型

开启子进程的两种方式 # # # 方式一: # from multiprocessing import Process # import time # # def task(x): # print('%s is running' %x) # time.sleep(3) # print('%s is done' %x) # # if __name__ == '__main__': # # Process(target=task,kwargs={'x':'子进程'}) # p=Process(tar

进程,互斥锁,生产者消费者,线程

进程,互斥锁,生产者消费者,线程 一.僵尸进程与孤儿进程 代码演示 ''' 僵尸进程(有坏处): - 在子进程结束后,主进程没有正常结束,子进程的PID不会被回收. 缺点: - 操作系统中PID号是有限的,比如子进程PID号无法正常回收,则会占用PID号. - 资源浪费 - 若PID号满了,则无法创建新的进程. 孤儿进程(没有坏处): - 在子进程没有结束时,主进程没有"正常结束",子进程PID不会被回收. - 操作系统优化机制(孤儿院): 当主进程意外终止,操作系统会检测是否有正在运

Python并发编程03/僵尸孤儿进程,互斥锁,进程之间的通信

目录 Python并发编程03/僵尸孤儿进程,互斥锁,进程之间的通信 1.昨日回顾 2.僵尸进程和孤儿进程 2.1僵尸进程 2.2孤儿进程 2.3僵尸进程如何解决? 3.互斥锁,锁 3.1互斥锁的应用 3.2Lock与join的区别 4.进程之间的通信 进程在内存级别是隔离的 4.1基于文件通信 (抢票系统) 4.2基于队列通信 Python并发编程03/僵尸孤儿进程,互斥锁,进程之间的通信 1.昨日回顾 1.创建进程的两种方式: 函数, 类. 2.pid: os.getpid() os.get

Java使用FileLock实现Java进程互斥锁

原理:JDK的nio包中FileLock实现类似Linux fcntl的文件锁, 可使文件被进程互斥访问.  借助此功能, 可以实现强大的Java进程互斥锁, 从而在应用层面保证同一时间只有惟一的Jar应用进程在运行! 避免某些因素导致jar重复执行, 多个进程产生竞争,破坏业务数据. (当然, 你可以借助类似ubuntu的upstart脚本或者ps -p <pid>之类的做法来做到相同的功能).实现: package test; import java.io.File; import jav

10.22进程互斥锁,队列,堆栈,线程

进程互斥锁 让并发变成串行,牺牲了执行效率,保证了数据的安全. 在程序并发执行时,如果需要修改数据就使用互斥锁. 队列 相当于内存中的空间. 可以存放多个数据,必须排队,遵循先进先出的顺序. from multiprocessing import Queue #调用队列类,实例化队列对象q q = Queue(5) #若传参,队列中就可以存放5个数据 q = Queue() #若不传参,则队列中可以存放无限个数据 q.get() #获取数据 q.put() #添加数据,满了就报错 q.empty

死锁现象与解决方案,开启线程的2种方式,守护线程,线程VS进程,线程互斥锁,信号量

死锁现象与解决方案 from threading import Thread,Lock,active_count import time mutexA=Lock() # 锁1 mutexB=Lock() # 锁2 class Mythread(Thread): def run(self): self.f1() self.f2() def f1(self): mutexA.acquire() print('%s 拿到A锁' %self.name) mutexB.acquire() print('%

守护进程,互斥锁,IPC,队列,生产者与消费者模型

小知识点:在子进程中不能使用input输入! 一.守护进程 守护进程表示一个进程b 守护另一个进程a 当被守护的进程结束后,那么守护进程b也跟着结束了 应用场景:之所以开子进程,是为了帮助主进程完成某个任务,然而,如果主进程认为自己的事情一旦做完了就没有必要使用子进程了,就可以将子进程设置为守护进程 例如:在运行qq的过程,开启一个进程,用于下载文件,然而文件还没有下载完毕,qq就退出了,下载任务也应该跟随qq的退出而结束. from multiprocessing import Process

35 守护进程 互斥锁 IPC 共享内存 的方式 生产者消费者模型

守护进程 进程:一个正在运行的程序. 主进程创建守护进程: 1.守护进程会在主进程代码执行结束后就终止, 2.守护进程内无法再开启子进程,否则抛出异常. 注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止. 例子:from multiprocessing import Processimport time def task(): print('老了....') time.sleep(2) print('睡了一会..') if __name__ == '__main__': prin

python并发编程-进程理论-进程方法-守护进程-互斥锁-01

操作系统发展史(主要的几个阶段) 初始系统 1946年第一台计算机诞生,采用手工操作的方式(用穿孔卡片操作) 同一个房间同一时刻只能运行一个程序,效率极低(操作一两个小时,CPU一两秒可能就运算完了) 联机批处理系统 脱机批处理系统 多道程序系统 1.空间上的复用 ? 多个程序公用一套计算机硬件 2.时间上的复用 ? 切换+保存状态 ? 保存状态:保存当前的运行状态,下次接着该状态继续执行 ? 切换的两种情况 ? (1) 当一个程序遇到 I/O 操作(不需要使用CPU),操作系统会剥夺该程序的C