今日内容

1、守护进程vs 守护线程(*)

2、互斥锁(**)

3、信号量(**)

4、生产者消费者模型(*****)

5、GIL(什么时候用进程,什么时候用线程)(*****)

 

一、守护进程和守护线程

1、守护进程  (分出去的进程设置成守护进程)

  守护进程不能开启子进程

#守护进程
from multiprocessing import Process
import os,time,random

def task():
    print("%s is running"%os.getpid())
    time.sleep(2)
    print("%s is done"%os.getpid())
    # p=Process(target=time.sleep,args=(3,))
    # p.start()

if __name__=="__main__":
    p=Process(target=task)
    p.daemon=True  #1、
    p.start()
    print("")
守护进程
举例说明守护进程的应用场景:
假设有两个任务要干,要玩出并发的效果,使用进程的话可以让主进程
执行一个任务,然后开启一个子进程执行一个任务。

如果这两个任务毫无关系,那么就像上面这么做就可以
如果主进程的任务在执行完毕后,子进程的任务没有存在的意义了
那么该子进程应该在开启之前就被设置成守护进程
# 迷惑人的例子
# 主进程代码运行完毕,守护进程就会结束
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也执行了,但是随即被终止
迷惑人的例子

  总结  :主进程运行完毕,守护进程也会随之结束

2、守护线程 

  一个进程开启了多个线程

 (1)守护线程能开启子线程

#守护线程:等到该进程内所有非守护线程都运行完才死掉
from multiprocessing import Process
from threading import Thread
import os,time,random

def task():
    t=Thread(target=time.sleep,args=(3,))
    t.start()
    print("%s is running"% os.getpid())
    time.sleep(2)
    print("%s is done"%os.getpid())
if __name__=="__main__":
    t=Thread(target=task)
    t.daemon=True #1、必须在t.start()之前2:守护线程可以开启子线程
    t.start()
    t.join()
    print("")
守护线程

(2)迷惑人的例子  ————守护线程

      其中非守护线程还没有结束(开启线程的目的是为了执行完毕函数)

#迷惑人的例子:守护线程
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(2)
    print("end456")

if __name__=="__main__":
    t1=Thread(target=foo)
    t2=Thread(target=bar)
    t1.daemon=True
    t1.start()
    t2.start()
    print("main_____")
# 123
# 456
# main_____
# end123
# end456
迷惑人的例子——守护线程

 

3、总结:

    为什么守护进程内不让开启子进程?

    主进程结束之后守护线程就会死掉(在这个进程中所有的非守护线程都运行完)

 主线程什么时候结束?

    主进程死掉(所有的线程结束后) 接着守护进程就会死掉

 二、互斥锁

1、互斥锁进程

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

def task():
    print("%s print 1"%os.getpid())
    time.sleep(random.randint(1,3))
    print("%s print 2"%os.getpid())
    time.sleep(random.randint(1, 3))
    print("%s print 3" % os.getpid())

if __name__=="__main__":
    p1=Process(target=task)
    p2=Process(target=task)
    p3=Process(target=task)
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()
1、low的做法
from multiprocessing import Process,Lock
import os,time,random

def task(mutex):
    mutex.acquire()
    print("%s print 1"%os.getpid())
    time.sleep(random.randint(1,3))
    print("%s print 2"%os.getpid())
    time.sleep(random.randint(1, 3))
    print("%s print 3" % os.getpid())
    mutex.release()
if __name__=="__main__":
    # p1=Process(target=task)
    # p2=Process(target=task)
    # p3=Process(target=task)
    # p1.start()
    # p1.join()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()
    mutex=Lock()
    p1 = Process(target=task,args=(mutex,))
    p2 = Process(target=task,args=(mutex,))
    p3 = Process(target=task,args=(mutex,))
    p1.start()
    p2.start()
    p3.start()
2、改进的互斥锁方法

2、模拟抢票的例子

from multiprocessing import Process,Lock
import json
import os,time,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 read_f:
        dic=json.load(read_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())

def task(mutex):
    search()
    mutex.acquire()
    get()
    mutex.release()
if __name__=="__main__":
    # for i in range(20):
    #     p=Process(target=task)
    #     p.start()
    #     p.join()
    mutex=Lock()
    for i in range(20):
        p=Process(target=task,args=(mutex,))
        p.start()
        p.join()
模拟抢票的例子

3、线程互斥锁

# 线程互斥锁
from threading import Thread,Lock
import time
n=100
def task():
    global n
    with mutex:
        temp=n
        time.sleep(0.1)
        n=temp-1
if __name__=="__main__":
    mutex=Lock()
    t_1=[]
    for i in range(100):
        t=Thread(target=task)
        t_1.append(t)
        t.start()
    for t in t_1:
        t.join()
    print(n)
线程互斥锁

三、信号量(和进程池不一样)

例子:抢公共厕所(假如进去10个人,十把钥匙,结束一个就释放钥匙,然后进去一个)

1、进程的信号量:

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):
        for i in range(10):
            p=Process(target=task,args=(sm,))
            p.start()
信号量

2、小心锁与锁之间的嵌套

(1)管道和队列都是用的内存的空间

(2)队列是基于管道加锁实现的

(3)如果对管道感兴趣就看博客   队列推荐使用

3、  进程Queue 和线程Queue 

不能直接放视频,应该直接放路径或者是链接

(1)

from multiprocessing import Queue #进程队列

# import queue  #线程队列
q=Queue(3)

q.put({"a":1})
q.put("xxxxx")
q.put(2)
q.put(4)

print(q.get())
print(q.get())
print(q.get())
print(q.get())

(2)队列的功能————先进先出

from multiprocessing import Queue #进程队列
import queue  #线程队列
q=queue.Queue(3)
q.put({"a":1})
q.put("xxxxx")
q.put(2)
q.put(4)

print(q.get())
print(q.get())
print(q.get())
print(q.get())
队列
# 优先级队列
from multiprocessing import Queue #进程队列
import queue  #线程队列
q=queue.PriorityQueue(3)
q.put((10,{"a":1}))
q.put((-1,"xxxxx"))
q.put((0,2))

print(q.get())
print(q.get())
print(q.get())
# (-1, 'xxxxx')
# (0, 2)
# (10, {'a': 1})
优先级队列

(3)堆栈————后进先出

# 堆栈
from multiprocessing import Queue #进程队列
import queue  #线程队列
q=queue.LifoQueue(3)
q.put({"a":1})
q.put("xxxxx")
q.put(2)

print(q.get())
print(q.get())
print(q.get())
print(q.get())
# 2
# xxxxx
# {'a': 1}
堆栈

 四、生产者和消费者模型

  模型指的概念

    生产者消费者可以实现程序的解耦  

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

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

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

if __name__=="__main__":
    q=Queue()
    p=Process(target=producer,args=(q,))
    c=Process(target=consumer,args=(q,))
    p.start()
    c.start()
    print("")

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))
生产者和消费者 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()

    p.join()
    q.put(None)
    print("")
生产者消费者模型