04并发编程(僵尸、孤儿、守护进程+消息队列+线程理论)

并发编程

僵尸进程与孤儿进程

# 僵尸进程 进程代码运行结束之后并没有直接结束而是需要等待回收子进程资源才能结束 # 孤儿进程 即主进程已经死亡(非正常)但是子进程还在运行

守护进程

守护进程:即守护着某个进程 一旦这个进程结束那么也随之结束 from multiprocessing import Process import time def test(name): print('总管:%s is running' % name) time.sleep(3) print('总管:%s is over' % name) if __name__ == '__main__': p = Process(target=test, args=('jason',)) p.daemon = True # 设置为守护进程(一定要放在start语句上方) p.start() print("皇帝jason寿终正寝") time.sleep(0.1)

互斥锁

问题:并发情况下操作同一份数据 极其容易造成数据错乱 解决措施:将并发变成串行 虽然降低了效率但是提升了数据的安全 锁就可以实现将并发变成串行的效果 行锁、表锁 使用锁的注意事项 在主进程中产生 交由子进程使用 1.一定要在需要的地方加锁 千万不要随意加 2.不要轻易的使用锁(死锁现象) # 在以后的编程生涯中 几乎不会接触到自己操作锁的情况 import json from multiprocessing import Process, Lock import time import random # 查票 def search(name): with open(r'data.txt', 'r', encoding='utf8') as f: data_dict = json.load(f) ticket_num = data_dict.get('ticket_num') print('%s查询余票:%s' % (name, ticket_num)) # 买票 def buy(name): # 先查票 with open(r'data.txt', 'r', encoding='utf8') as f: data_dict = json.load(f) ticket_num = data_dict.get('ticket_num') # 模拟一个延迟 time.sleep(random.random()) # 判断是否有票 if ticket_num > 0: # 将余票减一 data_dict['ticket_num'] -= 1 # 重新写入数据库 with open(r'data.txt', 'w', encoding='utf8') as f: json.dump(data_dict, f) print('%s: 购买成功' % name) else: print('不好意思 没有票了!!!') def run(name,mutex): search(name) mutex.acquire() # 抢锁 buy(name) mutex.release() # 释放锁 if __name__ == '__main__': mutex = Lock() for i in range(1, 11): p = Process(target=run, args=('用户%s' % i,mutex)) p.start()

消息队列

队列:先进先出 from multiprocessing import Queue q = Queue(5) # 括号内可以填写最大等待数 # 存放数据 q.put(111) q.put(222) # print(q.full()) # False 判断队列中数据是否满了 q.put(333) q.put(444) q.put(555) # print(q.full()) # q.put(666) # 超出范围原地等待 直到有空缺位置 # 提取数据 print(q.get()) print(q.get()) print(q.get()) print(q.get()) print(q.get()) # print(q.get()) # 没有数据之后原地等待直到有数据为止 print(q.get_nowait()) # 没有数据立刻报错 """ full和get_nowait能否用于多进程情况下的精确使用 不能!!! 队列的使用就可以打破进程间默认无法通信的情况 """

IPC机制

from multiprocessing import Queue, Process def producer(q): q.put("子进程p放的数据") def consumer(q): print('子进程c取的数据',q.get()) if __name__ == '__main__': q = Queue() p = Process(target=producer, args=(q,)) c = Process(target=consumer, args=(q,)) p.start() c.start() # q.put('主进程放的数据') # p = Process(target=consumer, args=(q,)) # p.start() # p.join() # print(q.get()) # print('主')

生产者消费者模型

""" 生产者 负责产生数据(做包子的) 消费者 负责处理数据(吃包子的) 该模型需要解决恭喜不平衡现象 """ from multiprocessing import Queue, Process, JoinableQueue import time import random def producer(name, food, q): for i in range(10): print('%s 生产了 %s' % (name, food)) q.put(food) time.sleep(random.random()) def consumer(name, q): while True: data = q.get() print('%s 吃了 %s' % (name, data)) q.task_done() if __name__ == '__main__': # q = Queue() q = JoinableQueue() p1 = Process(target=producer, args=('大厨jason', '玛莎拉', q)) p2 = Process(target=producer, args=('印度阿三', '飞饼', q)) p3 = Process(target=producer, args=('泰国阿人', '榴莲', q)) c1 = Process(target=consumer, args=('班长阿飞', q)) p1.start() p2.start() p3.start() c1.daemon = True c1.start() p1.join() p2.join() p3.join() q.join() # 等待队列中所有的数据被取干净 print('主')

线程理论

什么是线程? 进程其实是一个资源单位 真正被CPU执行的其实是进程里面的线程 """ 进程类似于是工厂 线程类似于是工厂里面的一条条流水线 所有的进程肯定含有最少一个线程 """ 进程间数据默认是隔离的 但是同一个进程内的多个线程数据是共享的

开设线程的两种方式

""" 开设进程需要做哪些操作 1.重新申请一块内存空间 2.将所需的资源全部导入 开设线程需要做哪些操作 上述两个步骤都不需要 所以开设线程消耗的资源远比开设进程的少!!! """ from threading import Thread import time def test(name): print('%s is running' % name) time.sleep(3) print('%s is over' % name) t = Thread(target=test, args=('jason',)) t.start() print('主') class MyClass(Thread): def __init__(self,name): super().__init__() self.name = name def run(self): print('%s is running' % self.name) time.sleep(3) print('%s is over' % self.name) obj = MyClass('jason') obj.start() print('主线程')

线程对象的其他方法

1.join方法 2.获取进程号(验证同一个进程内可以开设多个线程) 3.active_count统计当前正在活跃的线程数 4.current_thread

守护线程

""" 主线程的结束意味着整个进程的结束 所以主线程需要等待里面所有非守护线程的结束才能结束 """ from threading import Thread from multiprocessing import Process import time def foo(): print(123) time.sleep(3) print("end123") def bar(): print(456) time.sleep(1) print("end456") if __name__ == '__main__': t1=Thread(target=foo) t2=Thread(target=bar) t1.daemon=True t1.start() t2.start() print("main-------")

线程数据共享

from threading import Thread money = 100 def test(): global money money = 999 t = Thread(target=test) t.start() t.join() print(money)

线程互斥锁

from threading import Thread, Lock from multiprocessing import Lock import time num = 100 def test(mutex): global num mutex.acquire() # 先获取num的数值 tmp = num # 模拟延迟效果 time.sleep(0.1) # 修改数值 tmp -= 1 num = tmp mutex.release() t_list = [] mutex = Lock() for i in range(100): t = Thread(target=test, args=(mutex,)) t.start() t_list.append(t) # 确保所有的子线程全部结束 for t in t_list: t.join() print(num)

TCP服务端实现并发

import socket from threading import Thread from multiprocessing import Process server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) def talk(sock): while True: try: data = sock.recv(1024) if len(data) == 0: break print(data.decode('utf8')) sock.send(data + b'gun dan!') except ConnectionResetError as e: print(e) break sock.close() while True: sock, addr = server.accept() print(addr) # 开设多进程或者多线程 t = Thread(target=talk, args=(sock,)) t.start()

练习

1.自行百度搜索什么是"乐观锁与悲观锁" 2.自行百度搜索什么是"消息队列" 3.自行百度搜索什么是"二十三种设计模式" # 平时就可以练习算法(冒泡 二分 插入 快排 堆排 桶排) 笔纸写出来的:冒泡 二分 插入 快排 能够描述出内部原理的:堆排 桶排 午间练习 将之前的TCP服务端变成多并发的效果

__EOF__

本文作者Pand_Xin
本文链接https://www.cnblogs.com/panda-xin/p/15881263.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Panda_Xin  阅读(93)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示