python 锁

内容概要

  • 进程对象及其他方法
  • 僵尸进程与孤儿进程
  • 守护进程
  • 互斥锁
  • 队列介绍
  • 进程间通信IPC机制
  • 生产者消费者模型
  • 线程相关知识点

进程对象及其他方法

如何查看进程的PID号
命令法:
windows: tasklist
         tasklist |findstr PID查看具体的进程
mac:     进入终端之后输入ps aux
	     ps aux|grep PID查看具体的进程

用python功能查看:
    from multiprocessing import Process,current_process
    pid = current_process().pid  # 查看当前进程的进程号
    p.terminate()   # 杀死当前进程,是告诉操作系统帮你去杀死当前进程 但是需要一定的时间 而代码的运行速度极快
    p.is_alive()     # 判断当前进程是否存活
    
    用OS模块的功能查看:
    import os
    os.getpid()  # 查看当前进程进程号
    os.getppid()  # 查看当前进程的父进程进程号
代码实现:
from multiprocessing import Process,current_process
import os
import time


def task(name):
    print(f'子进程{name}开始')
    # pid_1 = current_process().pid
    pid_1 = os.getpid()
    pid_2 = os.getppid()
    print(pid_1)
    print(pid_2)
    print(f'子进程运行{name}结束')


if __name__ == '__main__':
    # pid = current_process().pid
    pid = os.getpid()
    print(pid,'主')
    p = Process(target=task, args=('1',))
    p.start()
    time.sleep(3)   #  不能刚运行就杀死该程序
    p.terminate()
    time.sleep(2)
    print(p.is_alive())
    

僵尸进程与孤儿进程

# 僵尸进程
"""
死了但是没有死透
当你开设了子进程之后 该进程死后不会立刻释放占用的进程号
因为子进程要让父进程能够查看到它开设的子进程的一些基本信息 占用的pid号 运行时间
父进程会回收子进程占用的pid号等,父进程调用join方法等待子进程运行结束
所有的进程都会步入僵尸进程
	危险的僵尸进程: 父进程不死并且在无限制的创建子进程并且子进程也不结束
	
"""

# 孤儿进程
"""
子进程存活,父进程意外死亡
操作系统会开设一个“儿童福利院”专门管理孤儿进程回收相关资源
"""

守护进程

该子进程与主进程同生死,只要主进程结束,该守护进程一定会立即终止

方法:
p.daemon = True
注意: 将进程p设置成守护进程  这一句一定要放在start方法上面才有效否则会直接报错

互斥锁

多个进程操作同一份数据的时候,会出现数据错乱的问题
针对上述问题,解决方式就是加锁处理:将并发变成串行,牺牲效率但是保证了数据的安全

用法:
调用锁类生成互斥对象
mutex = Lock()

获得该互斥对象
mutex.accquire()

释放该互斥对象
mutex.release()

扩展: 行锁 表锁

注意:
1.锁不能轻易的使用,容易造成死锁现象(我们写代码一般不会用到,都是内部封装好的)
2.锁只在处理数据的部分加来保证数据安全(只在争抢数据的环节加锁处理即可)

代码实现:

def run(i, mutex):
    search(i)
    # 给买票环节加锁处理
    # 抢锁
    mutex.acquire()

    buy(i) # 操作数据
    # 释放锁
    mutex.release()


if __name__ == '__main__':
    # 在主进程中生成一把锁 让所有的子进程抢 谁先抢到谁先买票
    mutex = Lock()
    for i in range(1,11):
        p = Process(target=run, args=(i, mutex))
        p.start()

队列介绍

队列:管道+锁

管道:subprocess
stdin stdout stderr

队列:先进先出
堆栈:先进后出

使用方法:

from multiprocessing import Queue
# 创建一个队列
q = Queue  # 括号内可以传数字 标示生成的队列最大可以同时存放的数据量
# 往队列中存数据,当队列数据放满了之后 如果还有数据要放程序会阻塞 直到有位置让出来 不会报错
q.put('传的值')
# 去队列中取数据,队列中如果已经没有数据的话 get方法也会原地等待(阻塞)直到有数据为止
v = q.get()
v = q.get_nowait()  # 没有数据直接报错,信息为:queue.Empty
v = q.get(timeout=3)  # 没有数据之后原地等待三秒之后再报错,信息为:  queue.Empty
其他方法:
q.full()  # 判断当前队列是否满了
q.empty()  # 判断当前队列是否空了
"""
q.full()
q.empty()
q.get_nowait()
在多进程的情况下是不精确,因为下一瞬间队列可能被其他进程操作了
"""

代码实现:

from multiprocessing import Queue
q = Queue(3)
q.put(1)
q.put(2)
q.put(3)
try:
    print(q.full())
    v_1 = q.get()
    print(v_1)
    v_2 = q.get()
    print(v_2)
    v_3 = q.get()
    print(v_3)
    print(q.empty())
    v_4 = q.get(timeout=3)
    print(v_4)
except Exception as e:
    print('没有数据了')

IPC机制

进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
这里借助队列通信
使用方法:
同上

代码实现:

from multiprocessing import Queue,Process


def producer(q):
    q.put('hello')


if __name__ == '__main__':
    q = Queue()
    p = Process(target=(producer), args=(q,))
    p.start()
    res = q.get()
    print(res)

生产者消费者模型

生产者:生产/制造东西的
消费者:消费/处理东西的
该模型除了上述两个之外还需要一个媒介就是 队列

核心思想:
调用JoinableQueue模块用来计数,将消费者设置成守护进程,当q.join()运行时代表队列的数据已全部被消化,此时关闭主进程.
该模块功能:每当你往该队列中存入数据的时候 内部会有一个计数器+1,当你调用task_done的时候 计数器-1
q.join() 当计数器为0的时候 才往后运行

代码实现:

from multiprocessing import JoinableQueue,Process
import random
import time


def producer(x,porducer_name,q,name):
    for i in range(x):

        time.sleep(random.randint(1,3))
        q.put(name)
        print(f'{porducer_name}产生数据{name}')

def consumer(q,teacher_name):
    while True:
        time.sleep(random.randint(1,3))
        name=q.get()
        if name:
            print(f'{teacher_name}处理数据{name}')
            q.task_done()




if __name__ == '__main__':
    q = JoinableQueue()
    p2 = Process(target=producer,args=(4,'egon',q,'date'))
    p3 = Process(target=producer,args=(4,'tank',q,'数据'))
    p1 = Process(target=consumer, args=(q,'json'))
    p4 = Process(target=consumer, args=(q,'lili'))

    p2.start()
    p3.start()
    p1.daemon = True
    p4.daemon = True
    p4.start()
    p1.start()
    p2.join() # 如果不等这两个产生者,此时队列里没有数据,守护进程直接被干死了
    p3.join() # 如果不等这两个产生者,此时队列里没有数据,守护进程直接被干死了
    q.join()

posted @ 2020-04-23 22:12  Franciszw  阅读(216)  评论(0编辑  收藏  举报