进程互斥锁

基本概念

  • 临界资源: 一次仅允许一个进程使用的资源称为临界资源, 进程间采取互斥的方式, 共享临界资源
  • 进程互斥: 一个进程正在访问临界资源, 另一个要访问该资源的进程必须等待
  • 让并发变成串形, 牺牲了执行效率, 保证了数据的安全
  • 在程序并发执行时, 需要修改时使用

互斥锁的使用

# base_data--->{"ticket_num": 1}
# 模拟抢票软件
import json
import time
from multiprocessing import Process # 查看余票
def search(user):
with open('base_data', 'r', encoding='utf-8') as f:
dic = json.load(f)
ticket_num = dic.get('ticket_num')
print(f'用户{user}正在查看余票, 当前余票{ticket_num}张...') # 购买车票
def buy(user):
with open('base_data', 'r', encoding='utf-8') as f:
dic = json.load(f) # 阻塞
time.sleep(1) if dic.get('ticket_num') > 0:
dic['ticket_num'] -= 1
with open('base_data', 'w', encoding='utf-8') as f1:
json.dump(dic, f1)
print(f'用户[{user}]抢票成功!') else:
print(f'用户[{user}]抢票失败!') # 开始抢票
def run(user):
search(user)
buy(user) if __name__ == '__main__':
for i in range(10):
# 并发开启10个子进程
p = Process(target=run, args=(f'{i}',))
p.start()
'''
用户8正在查看余票, 当前余票1张...
用户6正在查看余票, 当前余票1张...
用户3正在查看余票, 当前余票1张...
用户0正在查看余票, 当前余票1张...
用户4正在查看余票, 当前余票1张...
用户2正在查看余票, 当前余票1张...
用户1正在查看余票, 当前余票1张...
用户7正在查看余票, 当前余票1张...
用户5正在查看余票, 当前余票1张...
用户9正在查看余票, 当前余票1张...
用户[8]抢票成功!
用户[6]抢票成功!
用户[3]抢票成功!
用户[4]抢票成功!
用户[1]抢票成功!
用户[5]抢票成功!
用户[2]抢票成功!
用户[0]抢票成功!
用户[7]抢票成功!
用户[9]抢票成功!
'''

使用进程锁将并发变成串行

# 模拟抢票软件
import json
import time
from multiprocessing import Process
from multiprocessing import Lock # 查看余票
def search(user):
with open('base_data', 'r', encoding='utf-8') as f:
dic = json.load(f)
ticket_num = dic.get('ticket_num')
print(f'用户[{user}]正在查看余票, 当前余票{ticket_num}张...') # 购买车票
def buy(user):
with open('base_data', 'r', encoding='utf-8') as f:
dic = json.load(f) time.sleep(1) if dic.get('ticket_num') > 0:
dic['ticket_num'] -= 1
with open('base_data', 'w', encoding='utf-8') as f1:
json.dump(dic, f1)
print(f'用户[{user}]抢票成功!') else:
print(f'用户[{user}]抢票失败!') # 开始抢票
def run(user, mutex):
# 上锁
mutex.acquire()
search(user)
buy(user)
# 解锁
mutex.release() if __name__ == '__main__':
# 调用Lock()类得到一个锁对象
mutex = Lock()
for i in range(10):
# 并发开启10个子进程
p = Process(target=run, args=(f'{i}', mutex))
p.start() '''
用户[0]正在查看余票, 当前余票1张...
用户[0]抢票成功!
用户[3]正在查看余票, 当前余票0张...
用户[3]抢票失败!
用户[2]正在查看余票, 当前余票0张...
用户[2]抢票失败!
用户[4]正在查看余票, 当前余票0张...
用户[4]抢票失败!
用户[8]正在查看余票, 当前余票0张...
用户[8]抢票失败!
用户[6]正在查看余票, 当前余票0张...
用户[6]抢票失败!
用户[7]正在查看余票, 当前余票0张...
用户[7]抢票失败!
用户[5]正在查看余票, 当前余票0张...
用户[5]抢票失败!
用户[1]正在查看余票, 当前余票0张...
用户[1]抢票失败!
用户[9]正在查看余票, 当前余票0张...
用户[9]抢票失败! '''

IPC

基本概念

  • inter-process communication 进程间通信
  • 进程间的数据是相互隔离的, 要想进行进程间的通信可以使用队列

队列

  • 进程间通信的一种方式, 支持多进程传入和取出数据
  • 遵循先进先出的原则
from multiprocessing import Queue

q = Queue(5)  # 队列中最多存放5个数据

# 填入数据
q.put('数据1')
q.put('数据2')
q.put('数据3')
q.put('数据4')
q.put('数据5')
# q.put('数据6') # 数据填满了继续存放, 程序会被卡住 # 查看队列是否填满
print(q.full()) # 队列满了, 则会会报错
# q.put_nowait('数据6') # 获取数据, 若队列中无数据可获取, 程序会卡住
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get()) # 队列中没有, 则会报错
# print(q.get_nowait()) # 判断队列是否为空
print(q.empty()) '''
True
数据1
数据2
数据3
数据4
数据5
True
'''

生产者消费者模型

基本概念

  • 生产者: 生产数据的
  • 消费者: 使用数据
  • 生产者消费者模型: 通过容器来解决生产者和消费者的之间的强耦合问题

代码实现

from multiprocessing import Process, Queue
import time # 定义生产者
def producer(q):
for i in range(5):
data = f'包子{i}'
q.put(data)
print(f'生产了{data}')
time.sleep(0.1) # 定义生产者
def consumer(q):
while True:
data = q.get()
print(f'吃了{data}') if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer, args=(q,))
p2 = Process(target=consumer, args=(q,)) p1.start()
p2.start()
print('主') '''

生产了包子0
吃了包子0
生产了包子1
吃了包子1
生产了包子2
吃了包子2
生产了包子3
吃了包子3
生产了包子4
吃了包子4
'''

线程

基本概念

  • 进程是资源单位, 线程才是CPU的执行单位, 进行运算调度的最小单位
  • 线程包含在进程之中, 是进程中的实际运作单位
  • 线程开销要远小于进程, 可以节省内存资源
  • 线程之间共享进程中的数据
  • 线程pid为主进程pid

创建线程

from threading import Thread
import time # 方式一
def task():
print('线程开启')
time.sleep(1)
print('线程结束') if __name__ == '__main__':
t = Thread(target=task)
t.start() # 方式二
class MyThread(Thread):
def run(self):
print('线程开启')
time.sleep(1)
print('线程结束') if __name__ == '__main__':
t = MyThread()
t.start()

线程互斥锁

from threading import Thread, Lock
import time n = 100 def task(i):
print(f'线程{i}启动...')
global n
temp = n
time.sleep(0.1)
n = temp - 1
print(n) if __name__ == '__main__':
for i in range(10):
t = Thread(target=task, args=(i + 1,))
t.start() '''
线程1启动...
线程2启动...
线程3启动...
线程4启动...
线程5启动...
线程6启动...
线程7启动...
线程8启动...
线程9启动...
线程10启动...
99
99
99
99
99
99
99
99
99
99
'''
from threading import Thread, Lock
import time mutex = Lock() n = 100 def task(i):
mutex.acquire()
print(f'线程{i}启动...')
global n
temp = n
time.sleep(0.1)
n = temp - 1
print(n)
mutex.release() if __name__ == '__main__':
for i in range(10):
t = Thread(target=task, args=(i + 1,))
t.start() '''
线程1启动...
99
线程2启动...
98
线程3启动...
97
线程4启动...
96
线程5启动...
95
线程6启动...
94
线程7启动...
93
线程8启动...
92
线程9启动...
91
线程10启动...
90
'''

Python3 并发编程2的更多相关文章

  1. Python3 并发编程4

    目录 Event事件 线程池与进程池 基本概念 使用方法 和信号量的区别 协程(coroutine) 基本概念 实现方式 多线程爬取梨视频 Event事件 用来控制线程的执行 e.isSet()查看对 ...

  2. Python3 并发编程3

    目录 GIL全局解释器锁 基本概念 多线程的作用 死锁现象 递归锁 信号量 线程队列 GIL全局解释器锁 基本概念 global interpreter lock 全局解释器锁 GIL不是Python ...

  3. Python3 并发编程小练习

    实现基于TCP协议套接字,服务端实现接收客户端的连接并发 # server.py import socket from threading import Thread server = socket. ...

  4. Python3 并发编程1

    目录 操作系统发展 穿孔卡片 批处理 多道技术(单核) 并发与并行 进程 程序与进程 进程调度 进程的三个状态 同步和异步 阻塞与非阻塞 僵尸进程与孤儿进程 守护进程 Python中的进程操作 Pro ...

  5. Python3 与 C# 并发编程之~ 进程篇

      上次说了很多Linux下进程相关知识,这边不再复述,下面来说说Python的并发编程,如有错误欢迎提出- 如果遇到听不懂的可以看上一次的文章:https://www.cnblogs.com/dot ...

  6. Python3 与 C# 并发编程之~ 协程篇

      3.协程篇¶ 去年微信公众号就陆陆续续发布了,我一直以为博客也汇总同步了,这几天有朋友说一直没找到,遂发现,的确是漏了,所以补上一篇 在线预览:https://github.lesschina.c ...

  7. Python3 与 C# 并发编程之~进程先导篇

      在线预览:http://github.lesschina.com/python/base/concurrency/1.并发编程-进程先导篇.html Python3 与 C# 并发编程之- 进程篇 ...

  8. Python3 与 C# 并发编程之~ 线程篇

      2.线程篇¶ 在线预览:https://github.lesschina.com/python/base/concurrency/3.并发编程-线程篇.html 示例代码:https://gith ...

  9. asyncio:python3未来并发编程主流、充满野心的模块

    介绍 asyncio是Python在3.5中正式引入的标准库,这是Python未来的并发编程的主流,非常重要的一个模块.有一个web框架叫sanic,就是基于asyncio,语法和flask类似,使用 ...

随机推荐

  1. PHP 在 Laravel 中动态隐藏 API 字段

    我最近在 Laravel Brasil 社区看到一个问题,结果比看起来更有趣.想象一下你有一个 UsersResource 用下面的实现: <?php namespace App\Http\Re ...

  2. 关于css中的字体样式

    1.决定字体的属性 color:字体颜色  属性值:单词,十六进制表示,rgb 2.字体大小 font-size:12px:属性值是整数字,不要带小数,单位是px叫做像素单位:凡是由像素拼成的图片我们 ...

  3. nyoj 76-超级台阶 (递推)

    76-超级台阶 内存限制:64MB 时间限制:1000ms 特判: No 通过数:8 提交数:12 难度:3 题目描述: 有一楼梯共m级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第m级,共 ...

  4. HashSet源码学习,基于HashMap实现

    HashSet源码学习 一).Set集合的主要使用类 1). HashSet 基于对HashMap的封装 2). LinkedHashSet 基于对LinkedHashSet的封装 3). TreeS ...

  5. 揭秘String类型背后的故事——带你领略汇编语言魅力

    字符串或串(String)是由数字.字母.下划线组成的一串字符.一般记为 s=“a1a2···an”(n>=0).它是编程语言中表示文本的数据类型.在程序设计中,字符串(string)为符号或数 ...

  6. Asp.Net Core下使用swagger生成api文档

    目录 一.前期准备 二.配置Swagger 三.参考 .Net Core中有两个集成NSwag的包,分别为Swashbuckle和NSwag.两者的配置大同小异.这里以NSwag为例. 一.前期准备 ...

  7. 老男孩python 自学day09 函数开始

    什么是函数? 函数用关键字def定义 语法: def 函数名(形参): 函数体 return 调用 函数名(实参) 命名规则:和变量一样 1. 由数字, 字母, 下划线组成 2. 不能数字开头. 更不 ...

  8. scrapy抓取斗鱼APP主播信息

    如何进行APP抓包 首先确保手机和电脑连接的是同一个局域网(通过路由器转发的网络,校园网好像还有些问题). 1.安装抓包工具Fiddler,并进行配置 Tools>>options> ...

  9. Java面向基础概述和三大特性

    Java 是面向对象的高级编程语言,类和对象是 Java 程序的构成核心.围绕着 Java 类和 Java 对象,有三大基本特性:封装是 Java 类的编写规范.继承是类与类之间联系的一种形式.而多态 ...

  10. 解决“无法完成域加入,原因是试图加入的域的SID与本计算机的SID相同

    原文链接:http://www.cnblogs.com/xiaoyou2018/p/10677437.html Windows server 2012 R2 解决"无法完成域加入,原因是试图 ...