守护线程、守护进程

目录

  • 守护进程
  • 守护线程
  • 互斥锁
  • 队列

    守护进程

    主进程创建守护进程
      其一:守护进程会在主进程代码执行结束后就终止
      其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
    注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止

from multiprocessing import Process
import os,time

def task():
    print('%s is starting' % os.getpid())
    time.sleep(1)
    print('%s is done' % os.getpid())

if __name__ == '__main__':
    p = Process(target=task)
    p.daemon = Ture   # 一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
    p.start()
    time.sleep(0.1)
    print('主')

结果:
9248 is starting
主

当主进程代码运行完了,守护进程也直接结束。

#主进程代码运行完毕,守护进程就会结束
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")


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

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

守护线程

无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁
需要强调的是:运行完毕并非终止运行

守护线程可以开启子线程,因为守护进程开启子进程的话可能会形成孤儿进程

#1.对主进程来说,运行完毕指的是主进程代码运行完毕
#2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
#1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,

#2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
from threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

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


t1=Thread(target=foo)
t2=Thread(target=bar)

t1.daemon=True
t1.start()
t2.start()
print("main-------")

互斥锁

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

# 并发运行,效率高,但竞争同一打印终端,带来了打印错乱
from multiprocessing import Process
import os,time,random

def task():
    print('aaaa %s' % os.getpid())
    time.sleep(random.randint(1, 3))
    print('bbbb %s' % os.getpid())
    time.sleep(random.randint(1, 3))
    print('cccc %s' % os.getpid())


if __name__ == '__main__':
    for i in range(3):
        p = Process(target=task)
        p.start()
# 由并发变成了串行,牺牲了运行效率,但避免了竞争
from multiprocessing import Process,Lock
import os,time,random

def task(lock):
    lock.acquire()
    print('aaaa %s' % os.getpid())
    time.sleep(random.randint(1, 3))
    print('bbbb %s' % os.getpid())
    time.sleep(random.randint(1, 3))
    print('cccc %s' % os.getpid())
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    for i in range(3):
        p = Process(target=task, args=(lock,))
        p.start()

part2:多个进程共享同一文件
文件当数据库,模拟抢票

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

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


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

    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(random.randint(1,3))
        with open('db.txt', 'w', encoding='utf-8') as wfile:
            json.dump(dic, wfile)
            print('购买成功!')

def main():
    search()
    get()


if __name__ == '__main__':
    for i in range(10):
        p = Process(target=main)
        p.start()

结果:
2104 剩余1张票
7484 剩余1张票
4884 剩余1张票
11260 剩余1张票
1544 剩余1张票
16232 剩余1张票
14136 剩余1张票
14332 剩余1张票
3300 剩余1张票
14596 剩余1张票
购买成功!
购买成功!
购买成功!
购买成功!
购买成功!
购买成功!
购买成功!
购买成功!
购买成功!
购买成功!
from multiprocessing import Process,Lock
import os,time
import json
import random


def search():
    with open('db.txt', encoding='utf-8') as f:
        dic = json.load(f)
        print('%s 剩余%s张票' % (os.getpid(), dic['count']))
    time.sleep(0.1)


def get():
    with open('db.txt', encoding='utf-8') as rfile:
        dic = json.load(rfile)
        time.sleep(0.1)
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(0.2)
        with open('db.txt', 'w', encoding='utf-8') as wfile:
            json.dump(dic, wfile)
            print('购买成功!%s' % os.getpid())


def main(lock):
    search()
    lock.acquire()
    get()
    lock.release()


if __name__ == '__main__':
    lock = Lock()
    for i in range(10):
        p = Process(target=main, args=(lock,))
        p.start()

Queue队列

进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的

 创建队列的类(底层就是以管道和锁定的方式实现):

  1. Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
    参数介绍:
  2. maxsize是队列中允许最大项数,省略则无大小限制。
q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.

q.get_nowait():同q.get(False)
q.put_nowait():同q.put(False)

q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样

生产者消费者模型

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

为什么要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者消费者模式

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

基于队列实现生产者消费者模型

from multiprocessing import Process,Queue
import os,time

def producer(q):
    for i in range(10):
        time.sleep(1)
        ret = '包子 %s'%i
        q.put(ret)
        print('%s 生产了 %s' % (os.getpid(), ret))


def consumer(q):
    while True:
        time.sleep(1.2)
        ret = q.get()
        if ret is None: break
        print('%s  吃了 %s'%(os.getpid(), ret))


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=(q,))
    c1 = Process(target=consumer, args=(q,))
    p1.start()
    c1.start()
    p1.join()
    q.put(None)
    print('生产完了!')

你可能感兴趣的:(Python)