Python队列、进程间通信、线程案例


Posted in Python onOctober 25, 2019

进程互斥锁

多进程同时抢购余票

# 并发运行,效率高,但竞争写同一文件,数据写入错乱
# data.json文件内容为 {"ticket_num": 1}
import json
import time
from multiprocessing import Process
def search(user):
  with open('data.json', 'r', encoding='utf-8') as f:
    dic = json.load(f)
  print(f'用户{user}查看余票,还剩{dic.get("ticket_num")}...')
def buy(user):
  with open('data.json', 'r', encoding='utf-8') as f:
    dic = json.load(f)

  time.sleep(0.1)
  if dic['ticket_num'] > 0:
    dic['ticket_num'] -= 1
    with open('data.json', 'w', encoding='utf-8') as f:
      json.dump(dic, f)
    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()

使用锁来保证数据安全

# data.json文件内容为 {"ticket_num": 1}
import json
import time
from multiprocessing import Process, Lock
def search(user):
  with open('data.json', 'r', encoding='utf-8') as f:
    dic = json.load(f)
  print(f'用户{user}查看余票,还剩{dic.get("ticket_num")}...')
def buy(user):
  with open('data.json', 'r', encoding='utf-8') as f:
    dic = json.load(f)

  time.sleep(0.2)
  if dic['ticket_num'] > 0:
    dic['ticket_num'] -= 1
    with open('data.json', 'w', encoding='utf-8') as f:
      json.dump(dic, f)
    print(f'用户{user}抢票成功!')

  else:
    print(f'用户{user}抢票失败')
def run(user, mutex):
  search(user)
  mutex.acquire() # 加锁
  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()

进程互斥锁:

让并发变成串行,牺牲了执行效率,保证了数据安全

在程序并发时,需要修改数据使用

队列

队列遵循的是先进先出

队列:相当于内存中一个队列空间,可以存放多个数据,但数据的顺序是由先进去的排在前面。

q.put() 添加数据

q.get() 取数据,遵循队列先进先出

q.get_nowait() 获取队列数据, 队列中没有就会报错

q.put_nowait 添加数据,若队列满了也会报错

q.full() 查看队列是否满了

q.empty() 查看队列是否为空

from multiprocessing import Queue

# 调用队列类,实例化队列对象
q = Queue(5)  # 队列中存放5个数据

# put添加数据,若队列里的数据满了就会卡住
q.put(1)
print('进入数据1')
q.put(2)
print('进入数据2')
q.put(3)
print('进入数据3')
q.put(4)
print('进入数据4')
q.put(5)
print('进入数据5')

# 查看队列是否满了
print(q.full())

# 添加数据, 若队列满了也会报错
q.put_nowait(6)

# q.get() 获取的数据遵循先进先出
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
# print(q.get())
print(q.get_nowait())  # 获取队列数据, 队列中没有就会报错

# 判断队列是否为空
print(q.empty())
q.put(6)
print('进入数据6')

进程间通信

IPC(Inter-Process Communication)

进程间数据是相互隔离的,若想实现进程间通信,可以利用队列

from multiprocessing import Process, Queue
def task1(q):
  data = 'hello 你好'
  q.put(data)
  print('进程1添加数据到队列')
def task2(q):
  print(q.get())
  print('进程2从队列中获取数据')
if __name__ == '__main__':
  q = Queue()

  p1 = Process(target=task1, args=(q, ))
  p2 = Process(target=task2, args=(q, ))
  p1.start()
  p2.start()
  print('主进程')

生产者与消费者

在程序中,通过队列生产者把数据添加到队列中,消费者从队列中获取数据

from multiprocessing import Process, Queue
import time


# 生产者
def producer(name, food, q):
  for i in range(10):
    data = food, i
    msg = f'用户{name}开始制作{data}'
    print(msg)
    q.put(data)
    time.sleep(0.1)
# 消费者
def consumer(name, q):
  while True:
    data = q.get()
    if not data:
      break

    print(f'用户{name}开始吃{data}')
if __name__ == '__main__':
  q = Queue()
  p1 = Process(target=producer, args=('neo', '煎饼', q))
  p2 = Process(target=producer, args=('wick', '肉包', q))

  c1 = Process(target=consumer, args=('cwz', q))
  c2 = Process(target=consumer, args=('woods', q))

  p1.start()
  p2.start()
  
  c1.daemon = True
  c2.daemon = True
  c1.start()
  c2.start()
  print('主')

线程

线程的概念

进程与线程都是虚拟单位

进程:资源单位

线程:执行单位

开启一个进程,一定会有一个线程,线程才是真正执行者

开启进程:

  • 开辟一个名称空间,每开启一个进程都会占用一份内存资源
  • 会自带一个线程

开启线程:

  • 一个进程可以开启多个线程
  • 线程的开销远小于进程

注意:线程不能实现并行,线程只能实现并发,进程可以实现并行

线程的两种创建方式

from threading import Thread
import time
# 创建线程方式1
def task():
  print('线程开启')
  time.sleep(1)
  print('线程结束')

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

线程对象的方法

from threading import Thread
from threading import current_thread
import time

def task():
  print(f'线程开启{current_thread().name}')
  time.sleep(1)
  print(f'线程结束{current_thread().name}')
if __name__ == '__main__':
  t = Thread(target=task)
  print(t.isAlive())
  # t.daemon = True
  t.start()
  print(t.isAlive())

线程互斥锁

线程之间数据是共享的

from threading import Thread
from threading import Lock
import time

mutex = Lock()
n = 100

def task(i):
  print(f'线程{i}启动')
  global n
  mutex.acquire()
  temp = n
  time.sleep(0.1)
  n = temp - 1
  print(n)
  mutex.release()
  
if __name__ == '__main__':
  t_l = []
  for i in range(100):
    t = Thread(target=task, args=(i, ))
    t_l.append(t)
    t.start()

  for t in t_l:
    t.join()

  print(n)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python 2.6.6升级到python 2.7.x版本的方法
Oct 09 Python
使用Python生成XML的方法实例
Mar 21 Python
浅谈Python基础之I/O模型
May 11 Python
基于Python_脚本CGI、特点、应用、开发环境(详解)
May 23 Python
Python实现运行其他程序的四种方式实例分析
Aug 17 Python
放弃 Python 转向 Go语言有人给出了 9 大理由
Oct 20 Python
python2.x实现人民币转大写人民币
Jun 20 Python
django session完成状态保持的方法
Nov 27 Python
Python3中urlencode和urldecode的用法详解
Jul 23 Python
python中threading开启关闭线程操作
May 02 Python
简单介绍Python的第三方库yaml
Jun 18 Python
PYTHON 使用 Pandas 删除某列指定值所在的行
Apr 28 Python
python银行系统实现源码
Oct 25 #Python
python Event事件、进程池与线程池、协程解析
Oct 25 #Python
python实现简单银行管理系统
Oct 25 #Python
Python银行系统实战源码
Oct 25 #Python
python实现银行管理系统
Oct 25 #Python
Django视图扩展类知识点详解
Oct 25 #Python
Python装饰器使用你可能不知道的几种姿势
Oct 25 #Python
You might like
Yii框架使用魔术方法实现跨文件调用功能示例
2017/05/20 PHP
对于Laravel 5.5核心架构的深入理解
2018/02/22 PHP
基于jquery实现漂亮的动态信息提示效果
2011/08/02 Javascript
用box固定长宽实现图片自动轮播js代码
2014/06/09 Javascript
input:checkbox多选框实现单选效果跟radio一样
2014/06/16 Javascript
JQuery基础语法小结
2015/02/27 Javascript
js控制页面的全屏展示和退出全屏显示的方法
2015/03/10 Javascript
JS 实现倒计时数字时钟效果【附实例代码】
2016/03/30 Javascript
每日十条JavaScript经验技巧(二)
2016/06/23 Javascript
BootStrap的table表头固定tbody滚动的实例代码
2016/08/24 Javascript
jQuery实现的无限级下拉菜单功能示例
2016/09/12 Javascript
微信小程序 倒计时组件实现代码
2016/10/24 Javascript
谈谈因Vue.js引发关于getter和setter的思考
2016/12/02 Javascript
js实现带进度条提示的多视频上传功能
2020/12/13 Javascript
Vue 2.0学习笔记之使用$refs访问Vue中的DOM
2017/12/19 Javascript
nodejs超出最大的调用栈错误问题
2017/12/27 NodeJs
JS实现select选中option触发事件操作示例
2018/07/13 Javascript
jquery获取select选中值的文本,并赋值给另一个输入框的方法
2018/08/21 jQuery
微信小程序自定义键盘 内部虚拟支付
2018/12/20 Javascript
一个因@click.stop引发的bug的解决
2019/01/08 Javascript
ES6基础之默认参数值
2019/02/21 Javascript
关于引入vue.js 文件的知识点总结
2020/01/28 Javascript
jquery实现加载更多"转圈圈"效果(示例代码)
2020/11/09 jQuery
python构造函数init实例方法解析
2020/01/19 Python
Python和Anaconda和Pycharm安装教程图文详解
2020/02/04 Python
详解python命令提示符窗口下如何运行python脚本
2020/09/11 Python
selenium+python实现基本自动化测试的示例代码
2021/01/27 Python
澳大利亚领先的睡衣品牌:Peter Alexander
2016/08/16 全球购物
经典演讲稿汇总
2014/05/19 职场文书
旅游专业毕业生自荐书
2014/06/30 职场文书
门卫岗位职责说明书
2014/08/18 职场文书
“三支一扶”支教教师思想汇报
2014/09/13 职场文书
本科毕业论文指导教师评语
2014/12/30 职场文书
小学副班长竞选稿
2015/11/21 职场文书
go语言中切片与内存复制 memcpy 的实现操作
2021/04/27 Golang
试了下Golang实现try catch的方法
2021/07/01 Golang