进程通信

布满荆棘的人生 2022-05-16 01:59 414阅读 0赞

1.独立的进程内存空间与共享的服务器进程空间

进程是独立的,互不干扰的独立内存空间

70

打印出a为1

也就是说,主进程中的a不受子进程中a的干扰,他们是相互独立的

那进程之间怎么通信那?

进程间通信的解决方案

70 1

创建一个服务器进程并返回一个管理器,管理器开辟一块空间(用于进程间数据共享)并返回一个代理,把这个代理通过args传递给其他进程,其他进程就可以通过这个代理访问共享的空间了。

  1. from multiprocessing import Manager,Process
  2. mgr = Manager() #创建服务器进程,并返回与其通信的管理器
  3. list = mgr.list() #通过管理器在服务器进程中开辟一个列表空间,并返回一个代理
  4. print(list)
  5. def func(list):
  6. list.append('a')
  7. #把列表传递给子进程,子进程就可以通过这个代理,来通过共享空间来进行通信
  8. p = Process(target=func,args=(list,))
  9. p.start()
  10. p.join()
  11. print(list)
  12. []
  13. ['a']

2.线程间共享的全局变量与同步锁的基本概念

线程间全局变量的共享

线程属于同一个进程,因此它们之间共享内存区域。 因此全局变量是公共的。

  1. from threading import Thread
  2. a = 1
  3. def func():
  4. global a
  5. a = 2
  6. t = Thread(target=func)
  7. t.start()
  8. t.join()
  9. print(a)
  10. 2

共享内存间存在竞争问题

  1. from threading import Thread
  2. data = 0
  3. n = 10000000 #加减操作的次数,如果预期结果不出现,那就多加几个0
  4. def add(n):
  5. global data
  6. for i in range(n): #对全局变量data进行n次+1操作
  7. data += 1
  8. def sub(n):
  9. global data
  10. for i in range(n): #对全局变量data进行n次-1操作
  11. data -= 1
  12. t_add = Thread(target=add, args=(n,))
  13. t_sub = Thread(target=sub, args=(n,))
  14. t_add.start()
  15. t_sub.start()
  16. t_add.join()
  17. t_sub.join()
  18. print(data)
  19. -2225363

由于线程间共享内存存在竞争,全局变量data不会严格按照两个进程的全部操作完整进行(先加n,后减n,最后为零),会出现一定缺失。

使用锁来控制共享资源的访问

lock = th.Lock() 生成锁

lock.acquire() 使用锁

lock.release() 释放锁

或使用释放合一 with lock:

  1. import threading as th
  2. data = 0
  3. n = 10000000 #加减操作的次数
  4. lock = th.Lock() #生成一把锁
  5. def add(n):
  6. global data
  7. lock.acquire()
  8. for i in range(n): #对全局变量data进行n次+1操作
  9. data += 1
  10. lock.release()
  11. def sub(n):
  12. global data
  13. with lock:
  14. for i in range(n): #对全局变量data进行n次-1操作
  15. data -= 1
  16. t_add = th.Thread(target=add, args=(n,))
  17. t_sub = th.Thread(target=sub, args=(n,))
  18. t_add.start()
  19. t_sub.start()
  20. t_add.join()
  21. t_sub.join()
  22. print(data)
  23. 0

3.线程与进程安全队列

使用原因

安全队列自带锁,可以避免因竞争出现的结果有误问题。

线程安全队列

导入:import queue

  1. que = queue.Queue()
  • 入队: put(item) #队列满,put阻塞,下同
  • 出队: get() #队列空,get阻塞,下同
  • 测试空: empty() # 近似,小概率出现判断失误,如某一进程正在放数据
  • 测试满: full() # 近似
  • 队列长度: qsize() # 近似
  • 任务结束: task_done()
  • 等待完成: join()

进程安全队列

导入:from multiprocess import Manager

  1. mgr = Manager()
  2. que = mgr.Queue()
  • 入队: put(item)
  • 出队: get()
  • 测试空: empty() # 近似
  • 测试满: full() # 近似
  • 队列长度: qsize() # 近似

其他问题解释

问:队列算公共资源嘛?

答:如果只是一个线程/进程在使用,那么它并不算公共资源。 但是一旦多个线程/进程在同时使用,那么它就是一个公共资源。

问:我们是否需要对其加锁?

答:如果被当作公共资源使用,那么按理说是必须要加锁的。 但是,线程安全或进程安全的队列中已经帮我们实现了锁。 因此我们不需 要再自己使用锁来同步。

4.生产者与消费者模型

生产者与消费者模型的概念

70 2

所谓,生产者与消费者模型,本质上是把进程通信的问题分开考虑

生产者,只需要往队列里面生产资源(生产者不需要关心消费者)

消费者,只需要从队列里面消费资源(消费者也不需要关心生产者)

消费者与生产者模式的应用——Web服务器与Web框架之间的关系

70 3

生产者——-客户端

消费者——-web框架进程

安全队列——-web服务器

每当有客户端发送请求时,web服务器接受所有的用户请求,web框架负责从服务器中拿数据并分配线程。

多线程版本

  1. import threading as th
  2. import queue
  3. import random
  4. class Consume(th.Thread):
  5. def __init__(self,queue):
  6. super().__init__()
  7. self.queue=queue
  8. def run(self):
  9. while True:
  10. item=self.queue.get()
  11. print("消费者,消费了%s"%item)
  12. class Produce(th.Thread):
  13. def __init__(self,queue):
  14. super().__init__()
  15. self.queue= queue
  16. def run(self):
  17. while True:
  18. item = random.randint(0,99) #生成资源的随机编号
  19. self.queue.put(item)
  20. print("生产者,生产:%s"%item)
  21. queue = queue.Queue(3) #设置线程安全队列长度为3
  22. p = Produce(queue)
  23. c = Consume(queue)
  24. p.start()
  25. c.start()
  26. 生产者,生产:30
  27. 生产者,生产:46
  28. 生产者,生产:73
  29. 生产者,生产:83
  30. 消费者,消费了30
  31. 消费者,消费了46
  32. 生产者,生产:71
  33. 消费者,消费了73
  34. 生产者,生产:47
  35. 消费者,消费了83
  36. 生产者,生产:74
  37. 消费者,消费了71
  38. 生产者,生产:4
  39. 消费者,消费了47

多进程版本

  1. from multiprocessing import Process,Manager
  2. import random
  3. con_queue=Manager().Queue(3)
  4. class Consume(Process):
  5. def __init__(self,con_queue):
  6. super().__init__()
  7. self.queue=con_queue
  8. def run(self):
  9. while True:
  10. item=self.queue.get()
  11. print("消费者,消费:%s"%item)
  12. class Produce(Process):
  13. def __init__(self,con_queue):
  14. super().__init__()
  15. self.queue = con_queue
  16. def run(self):
  17. while True:
  18. item = random.randint(0,99)
  19. self.queue.put(item)
  20. print("生产者,生产:%s"%item)
  21. p = Produce(con_queue)
  22. c = Consume(con_queue)
  23. p.start()
  24. c.start()
  25. p.join()
  26. c.join()

发表评论

表情:
评论列表 (有 0 条评论,414人围观)

还没有评论,来说两句吧...

相关阅读

    相关 进程通信

    进程通信 什么是进程通信 进程通信三种方法 共享存储 管道通信 消息传递 总结 什么是进程通信 顾名思义

    相关 线程通信&进程通信

    进程和线程的区别: 对于进程来说,子进程是父进程的复制品,从父进程那里获得父进程的数据空间,堆和栈的复制品。 而线程,相对于进程而言,是一个更加接近于执行体的概念,可以和同

    相关 进程通信

    进程通信 操作系统会为不同的进程分配不同的独立的内存地址空间,不同的进程之间因此是无法直接访问其他进程的内存地址空间的,但是进程之间的通信又是必须要实现的,因此操作系统提

    相关 进程通信

    1.独立的进程内存空间与共享的服务器进程空间 进程是独立的,互不干扰的独立内存空间 ![70][] 打印出a为1 也就是说,主进程中的a不受子进程中a的干扰,他们是

    相关 进程通信

    1.进程通信:进程之间的信息交换 2.发展历程:低级进程通信—>高级进程通信 2.1 低级进程通信、高级进程通信之比较 <table> <thead>