并发编程-02 22

进程锁

当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。

不加锁

from multiprocessing import Process
import os

import time


def task(i):
    print("第%s个: 进程id号:%s开始进来了" % (i, os.getpid()))
    time.sleep(2)
    print("第%s个: 进程id号:%s开始走了" % (i, os.getpid()))



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

        
#运行结果 0: 进程id号:48292开始进来了
第1: 进程id号:21480开始进来了
第2: 进程id号:35124开始进来了
第3: 进程id号:54132开始进来了
第4: 进程id号:51000开始进来了
第0: 进程id号:48292开始走了
第1: 进程id号:21480开始走了
第2: 进程id号:35124开始走了
第3: 进程id号:54132开始走了
第4: 进程id号:51000开始走了

Process finished with exit code 0

加锁

由并发变成了串行,牺牲了运行效率,但避免了竞争

from multiprocessing import Process, Lock
import os

import time


def task(i, lock):
    # 开始上锁
    lock.acquire()
    print("第%s个: 进程id号:%s开始进来了" % (i, os.getpid()))
    time.sleep(2)
    print("第%s个: 进程id号:%s开始走了" % (i, os.getpid()))
    # 释放锁t
    lock.release()


if __name__ == '__main__':
    lock = Lock()  # 5个人用同一把锁
    for i in range(5):
        p = Process(target=task, args=(i, lock))
        p.start()
#运行结果 0: 进程id号:20004开始进来了
第0: 进程id号:20004开始走了
第1: 进程id号:48464开始进来了
第1: 进程id号:48464开始走了
第2: 进程id号:21696开始进来了
第2: 进程id号:21696开始走了
第3: 进程id号:39528开始进来了
第3: 进程id号:39528开始走了
第4: 进程id号:53084开始进来了
第4: 进程id号:53084开始走了

Process finished with exit code 0

没有加锁的情况,虽然实现了并发,但是数据不安全

加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。

进程间数据隔离

进程之间数据是互不影响的

"""
1. 进程之间数据是互不影响的
"""
from multiprocessing import Process

n = 10

def task():
    global n
    n = 100
    print('task:', n)


if __name__ == '__main__':
    # task()
    p = Process(target=task)
    p.start()
    print("main:", n)

Queue队列

线程优先级队列( Queue)

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

Queue模块中的常用方法:

- Queue.qsize() 返回队列的大小
- Queue.empty() 如果队列为空,返回True,反之False
- Queue.full() 如果队列满了,返回True,反之False
- Queue.full 与 maxsize 大小对应
- Queue.get([block[, timeout]])获取队列,timeout等待时间
- Queue.get_nowait() 相当Queue.get(False)
- Queue.put(item) 写入队列,timeout等待时间
- Queue.put_nowait(item) 相当Queue.put(item, False)
- Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
- Queue.join() 实际上意味着等到队列为空,再执行别的操作

先进先出

import queue

q=queue.Queue()
q.put('first')
q.put('second')
q.put('third')

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

#运行结果 
first
second
third

先进后出

import queue

q=queue.LifoQueue()
q.put('first')
q.put('second')
q.put('third')

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


#运行结果 
third
second
first

队列的优先级

import queue

q=queue.PriorityQueue()
#put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))

print(q.get())
print(q.get())
print(q.get())
'''
结果(数字越小优先级越高,优先级高的优先出队):
(10, 'b')
(20, 'a')
(30, 'c')
'''

生产者消费者模型

# 版本6:消费者多,生产者少
def producer(queue, food):
    for i in range(10):
        data = '%s:生产了第%s个%s' % (os.getpid(), i, food)
        # print(data)
        queue.put('第%s个%s' % (i, food))


def consumer(queue, name):
    while True:
        try:
            data = queue.get(timeout=3)
            if data is None: break
            time.sleep(0.2)

            print("消费者:%s,消费了:%s" % (name, data))
        except Exception as e:
            print(e)
            break

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=(q, '馒头'))
    p2 = Process(target=producer, args=(q, '花卷'))
    p3 = Process(target=producer, args=(q, '烧麦'))
    p1.start()
    p2.start()
    p3.start()

    p4 = Process(target=consumer, args=(q, 'egon'))
    p5 = Process(target=consumer, args=(q, 'ly'))
    p6 = Process(target=consumer, args=(q, 'tom'))
    p7 = Process(target=consumer, args=(q, 'qq'))
    p4.start()
    p5.start()
    p6.start()
    p7.start()

    # put(None) 放在这里不行,原因是先执行了主进程,放进了None,消费者先拿到None,程序直接结束了
    p1.join()
    p2.join()
    p3.join()

    q.put(None)
    q.put(None)

    print("end===========>")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值