并发编程: 生产消费模型、死锁与Rlock、线程、守护线程、信号量、锁

一、守护进程

二、互斥锁

三、抢票

四、进程间通讯

五、进程间通讯2

一、守护进程

"""
    进程间通讯的另一种方式 使用queue
    queue  队列
    队列的特点:
        先进的先出
        后进后出
        就像扶梯
"""
from multiprocessing import Process,Queue

# 基础操作 必须要掌握的
# 创建一个队列
# q = Queue()
# # 存入数据
# q.put("hello")
# q.put(["1","2","3"])
# q.put(1)
# # 取出数据
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())

# 阻塞操作 必须掌握
# q = Queue(3)
# # # 存入数据
# q.put("hello",block=False)
# q.put(["1","2","3"],block=False)
# q.put(1,block=False)
# # 当容量满的时候 再执行put 默认会阻塞直到执行力了get为止
# # 如果修改block=False 直接报错 因为没地方放了
# # q.put({},block=False)
#
# # # # 取出数据
# print(q.get(block=False))
# print(q.get(block=False))
# print(q.get(block=False))
# # 对于get   当队列中中没有数据时默认是阻塞的  直达执行了put
# # 如果修改block=False 直接报错 因为没数据可取了
# print(q.get(block=False))

# 了解
q = Queue(3)
q.put("q",timeout=3)
q.put("q2",timeout=3)
q.put("q3",timeout=3)
# 如果满了 愿意等3秒  如果3秒后还存不进去 就炸
# q.put("q4",timeout=3)

print(q.get(timeout=3))
print(q.get(timeout=3))
print(q.get(timeout=3))
# 如果没了 愿意等3秒  如果3秒后还取不到数据 就炸
print(q.get(timeout=3))

二、互斥锁

from multiprocessing import Process,Lock

# 进程间 内存空间是相互独立的
def task1(lock):
    lock.acquire()
    for i in range(10000):
        print("===")
    lock.release()

def task2(lock):
    lock.acquire()
    for i in range(10000):
        print("===============")
    lock.release()

def task3(lock):
    lock.acquire()
    for i in range(10000):
        print("======================================")
    lock.release()

if __name__ == ‘__main__‘:
    # 买了一把锁
    mutex = Lock()

    # for i in range(10):
    #     p = Process(target=)
    p1 = Process(target=task1,args=(mutex,))
    p2 = Process(target=task2,args=(mutex,))
    p3 = Process(target=task3,args=(mutex,))

    # p1.start()
    # p1.join()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()

    p1.start()
    p2.start()
    p3.start()

    print("over!")
    # 什么时候用锁?
    # 当多个进程 同时读写同一份数据 数据很可能就被搞坏了
    # 第一个进程写了一个中文字符的一个字节 cpu被切到另一个进程
    # 另一个进程也写了一个中文字符的一个字节
    # 最后文件解码失败
    # 问题之所以出现 是因为并发 无法控住顺序
    # 目前可以使用join来将所有进程并发改为串行

    # 与join的区别?
    # 多个进程并发的访问了同一个资源  将导致资源竞争(同时读取不会产生问题 同时修改才会出问题)
    # 第一个方案 加上join  但是这样就导致了 不公平  相当于 上厕所得按照颜值来
    # 第二个方案 加锁  谁先抢到资源谁先处理[
    # 相同点: 都变成了串行
    # 不同点:
    # 1.join顺序固定 锁顺序不固定!
    # 2.join使整个进程的任务全部串行  而锁可以指定哪些代码要串行

    # 锁使是什么?
    # 锁本质上就是一个bool类型的标识符  大家(多个进程) 在执行任务之前先判断标识符
    # 互斥锁 两个进程相互排斥

    # 注意 要想锁住资源必须保证 大家拿到锁是同一把

    # 怎么使用?
    # 在需要加锁的地方 lock.acquire() 表示锁定
    # 在代码执行完后 一定要lock.release() 表示释放锁
    # lock.acquire()
    # 放需要竞争资源的代码 (同时写入数据)
    # lock.release()

三、抢票

from multiprocessing import Process,Lock

# 进程间 内存空间是相互独立的
def task1(lock):
    lock.acquire()
    for i in range(10000):
        print("===")
    lock.release()

def task2(lock):
    lock.acquire()
    for i in range(10000):
        print("===============")
    lock.release()

def task3(lock):
    lock.acquire()
    for i in range(10000):
        print("======================================")
    lock.release()

if __name__ == ‘__main__‘:
    # 买了一把锁
    mutex = Lock()

    # for i in range(10):
    #     p = Process(target=)
    p1 = Process(target=task1,args=(mutex,))
    p2 = Process(target=task2,args=(mutex,))
    p3 = Process(target=task3,args=(mutex,))

    # p1.start()
    # p1.join()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()

    p1.start()
    p2.start()
    p3.start()

    print("over!")
    # 什么时候用锁?
    # 当多个进程 同时读写同一份数据 数据很可能就被搞坏了
    # 第一个进程写了一个中文字符的一个字节 cpu被切到另一个进程
    # 另一个进程也写了一个中文字符的一个字节
    # 最后文件解码失败
    # 问题之所以出现 是因为并发 无法控住顺序
    # 目前可以使用join来将所有进程并发改为串行

    # 与join的区别?
    # 多个进程并发的访问了同一个资源  将导致资源竞争(同时读取不会产生问题 同时修改才会出问题)
    # 第一个方案 加上join  但是这样就导致了 不公平  相当于 上厕所得按照颜值来
    # 第二个方案 加锁  谁先抢到资源谁先处理[
    # 相同点: 都变成了串行
    # 不同点:
    # 1.join顺序固定 锁顺序不固定!
    # 2.join使整个进程的任务全部串行  而锁可以指定哪些代码要串行

    # 锁使是什么?
    # 锁本质上就是一个bool类型的标识符  大家(多个进程) 在执行任务之前先判断标识符
    # 互斥锁 两个进程相互排斥

    # 注意 要想锁住资源必须保证 大家拿到锁是同一把

    # 怎么使用?
    # 在需要加锁的地方 lock.acquire() 表示锁定
    # 在代码执行完后 一定要lock.release() 表示释放锁
    # lock.acquire()
    # 放需要竞争资源的代码 (同时写入数据)
    # lock.release()

四、进程间通讯

"""
    IPC 指的是进程间通讯
        之所以开启子进程 肯定需要它帮我们完成任务 很多情况下 需要将数据返回给父进程
        然而 进程内存是物理隔离的
    解决方案:
    1.将共享数据放到文件中   就是慢
    2.管道   subprocess中的那个  管道只能单向通讯  必须存在父子关系
    3.共享一块内存区域  得操作系统帮你分配  速度快

"""

from multiprocessing import  Process,Manager
import time

def task(dic):
    print("子进程xxxxx")
    # li[0] = 1
    # print(li[0])
    dic["name"] = "xx"

if __name__ == ‘__main__‘:
    m = Manager()
    # li = m.list([100])
    dic = m.dict({})
    # 开启子进程
    p = Process(target=task,args=(dic,))
    p.start()
    time.sleep(3)
    print(dic)

五、进程间通讯2

"""
    进程间通讯的另一种方式 使用queue
    queue  队列
    队列的特点:
        先进的先出
        后进后出
        就像扶梯
"""
from multiprocessing import Process,Queue

# 基础操作 必须要掌握的
# 创建一个队列
# q = Queue()
# # 存入数据
# q.put("hello")
# q.put(["1","2","3"])
# q.put(1)
# # 取出数据
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())

# 阻塞操作 必须掌握
# q = Queue(3)
# # # 存入数据
# q.put("hello",block=False)
# q.put(["1","2","3"],block=False)
# q.put(1,block=False)
# # 当容量满的时候 再执行put 默认会阻塞直到执行力了get为止
# # 如果修改block=False 直接报错 因为没地方放了
# # q.put({},block=False)
#
# # # # 取出数据
# print(q.get(block=False))
# print(q.get(block=False))
# print(q.get(block=False))
# # 对于get   当队列中中没有数据时默认是阻塞的  直达执行了put
# # 如果修改block=False 直接报错 因为没数据可取了
# print(q.get(block=False))

# 了解
q = Queue(3)
q.put("q",timeout=3)
q.put("q2",timeout=3)
q.put("q3",timeout=3)
# 如果满了 愿意等3秒  如果3秒后还存不进去 就炸
# q.put("q4",timeout=3)

print(q.get(timeout=3))
print(q.get(timeout=3))
print(q.get(timeout=3))
# 如果没了 愿意等3秒  如果3秒后还取不到数据 就炸
print(q.get(timeout=3))

小结:

1.守护进程 **
    a守护b   b如果死了  a也就跟着死了

2.互斥锁 ******
    为什么使用锁?
    当多个进程对统一资源进行读写时 引发了数据错乱 解决方案就是变成串行
    1.join  把整个进程变成串行  并且顺序时固定的
    2.锁Lock  可以指定哪些代码出串行 并且对资源的竞争是公平的
    本质上就是一个标识符 True 或 False
    多个进程要保证使用同一把锁

3.进程间通讯  ***
    1.文件
    2.管道
    3.共享内存
        Manager  共享列表或字典
        Queue    是一个队列  带有阻塞效果

原文地址:https://www.cnblogs.com/wuzhengzheng/p/10268558.html

时间: 2024-08-23 18:18:05

并发编程: 生产消费模型、死锁与Rlock、线程、守护线程、信号量、锁的相关文章

【JAVA】wait和notify用法,附生产/消费模型

关于wait和notify的用法,网上已经有很多详细解释了,我只是简单的总结下. wait用于释放锁A,并让wait所在的线程阻塞.除非被持有锁A的其它线程执行notify来唤醒,它才能重新"活"过来. notify用于唤醒因为等待锁A而阻塞的线程,让它们做好竞争锁A的准备.如果有多个线程因等待锁A而被阻塞,notify只唤醒一个,唤醒所有用notifyAll. 参考下面的线程状态图,对理解wait和notify有很大的帮助. 总结: wait和notify通常和synchronize

Java生产消费模型—ArrayBlockingQueue详解

背景需求 生产消费模型是线程协作关系中十分常见的一种.通常,一个(多个)线程负责生产,一个(多个)线程可以从生产的列表中获取并消费:生产的内容可以按需求设计,可以是一个Integer,可以是String,可以Object,也可以是任意类型的对象,只要有生产消费的需求. 例如,厨师负责生产美食,放在桌子上,服务员负责取走(消费)美食.这里,厨师就扮演着生产者的身份,美食是生产的内容,服务员就扮演着消费者的身份. 下面用这个厨师与服务员的案例来分析下生产消费模型需要实现哪些功能才能满足需求: 如何实

并发编程-Java内存模型到底是什么

内存模型 在计算机CPU,内存,IO三者之间速度差异,为了提高系统性能,对这三者速度进行平衡. CPU 增加了缓存,以均衡与内存的速度差异: 操作系统增加了进程.线程,以分时复用 CPU,进而均衡 CPU 与 I/O 设备的速度差异: 编译程序优化指令执行次序,使得缓存能够得到更加合理地利用. 以上三种系统优化,对于硬件的效率有了显著的提升,但是他们同时也带来了可见性,原子性以及顺序性等问题.基于Cpu高速缓存的存储交互很好得解决了CPU和内存得速度矛盾,但是也提高了计算机系统得复杂度,引入了新

python学习笔记-Day11 (线程、进程、queue队列、生产消费模型、携程)

线程使用 ###方式一 import threading def f1(arg): print(arg) t = threading.Thread(target=f1, args=(123,)) t.start() # start会调用run方法执行 # t是threading.Thread类的一个对象 # t.start()就会以线程的方式执行函数,可以使用pycharm ctrl选择start方法 # 找到Thread类的start方法,在start方法的注释中就已经写明,会去调用run()

队列、生产消费模型.html

一.python 队列: 概述: import queue 都是在python内存中创建,python进程退出,则队列清空 可通过pycharm查看这些队列类的方法 先进先出队列: q = queun.Queue( [10] ) # 创建一个 "先进先出" 队列,最多接受10个数据,放第11个时会卡主,不加参数默认为0,即无限多个 q.qsize() # 查看当前队列中元素个数 q.maxsize # 队列最大个数 q.put(33, [ timeout=2] ) # 等待2秒,若2秒

Java并发编程(十)死锁

哲学家进餐问题 并发执行带来的最棘手的问题莫过于死锁了,死锁问题中最经典的案例就是哲学家进餐问题:5个哲学家坐在一个桌子上,桌子上有5根筷子,每个哲学家的左手边和右手边各有一根筷子.示意图如下: 哲学家进餐问题 并发执行带来的最棘手的问题莫过于死锁了,死锁问题中最经典的案例就是哲学家进餐问题:5个哲学家坐在一个桌子上,桌子上有5根筷子,每个哲学家的左手边和右手边各有一根筷子.示意图如下: 哲学家必须拿起左右两边的筷子才能进餐,如果他们同时拿起左手边的筷子,就会导致死锁.因为右手边的筷子被他右边的

生成器函数以及生产消费模型

1.生成器函数,即最终的输出用yield替代return,其他形式不变的函数,而且相比于return,输入yield函数不会立即停止 1 def test(): 2 print('你好') 3 return 10 4 def test_1(): 5 print('你好') 6 yield 10 7 a = test() 8 print(a) 9 b = test_1() 10 print(b) #<generator object test_1 at 0x00000000024F3570> 首

java并发编程(九)死锁

转载请注明出处:http://blog.csdn.net/ns_code/article/details/17200937 大部分代码并不容易产生死锁,死锁可能在代码中隐藏相当长的时间,等待不常见的条件地发生,但即使是很小的概率,一旦发生,便可能造成毁灭性的破坏.避免死锁是一件困难的事,遵循以下原则有助于规避死锁: 1.只在必要的最短时间内持有锁,考虑使用同步语句块代替整个同步方法: 2.尽量编写不在同一时刻需要持有多个锁的代码,如果不可避免,则确保线程持有第二个锁的时间尽量短暂: 3.创建和使

Java并发编程从入门到精通 - 第6章:线程池

1.什么是线程池(为什么使用线程池):2.Executor框架介绍:  Java 5中引入的,其内部使用了线程池机制,在java.util.cocurrent 包下,通过该框架来控制线程的启动.执行和关闭(使用该框架来创建线程池),可以简化并发编程的操作:  Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等:  ExecutorService接口继承自Executor接口,

《java并发编程实战》读书笔记1--线程安全性,内置锁,重入,状态

什么是线程安全? 当多个线程访问某个类时,不管这些的线程的执行顺序如何,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的. 哈哈书上的解释,还是翻译过来的,看了半天还是觉得有点奇怪.比如说 "类都能表现出正确的行为" 是毛线意思?在网上搜了一番 "线程安全就是说多线程访问同一代码,不会产生不确定的结果" 这样反而跟容易理解,果然读书要么读原版中文书要么读原版英文书,看英文的翻译版真的是蛋疼无比.说到这里,我以前貌似把