Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁
Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁
1. 生产消费者模型
定义:编程思想,模型,设计模式,理论等等,都是一种编程的方法,遇到类似的情况,套用即可.
生产者消费者模型三要素:
生产者: 产生数据的
消费者: 接收数据做进一步处理的
容器: 队列,起到缓冲的作用,平衡生产力与消费力,解耦.
代码示例:
from multiprocessing import Process
from multiprocessing import Queue
import time
import random def producer(q,name):
for i in range(1,6):
time.sleep(random.randint(1,2))
res = f'{i}号包子'
q.put(res)
print(f'生产者{name} 生产了{res}') def consumer(q,name):
while 1:
try:
food = q.get(timeout=3)
time.sleep(random.randint(1, 3))
print(f'\033[31;0m消费者{name} 吃了{food}\033[0m')
except Exception:
return if __name__ == '__main__':
q = Queue()
p1 = Process(target=producer,args=(q,'张三'))
p2 = Process(target=consumer,args=(q,'李四'))
p1.start()
p2.start()
2. 线程的理论知识
什么是线程
标准描述开启一个进程:开启一个进程:进程会在内存中开辟一个进程空间,将主进程的资料数据全部复制一份,线程会执行里面的代码.
***进程是资源单位, 线程是执行单位;是操作系统调度的最小单元,是进程中的实际运作单位.
线程vs进程
- 开启进程的开销非常大,比开启线程的开销大很多.
- 开启线程的速度非常快.要快几十倍到上百倍.
- 同一进程内线程与线程之间可以共享数据,进程与进程之间需借助队列等方法实现通信.
线程的应用
单个进程开启三个线程.并发的执行任务.
并发:一个cpu 看起来像是同时执行多个任务.
主线程子线程没有地位之分
一个主线程在干活,当干完活了,得等待其他线程干完活之后,才能结束本进程.
3. 开启线程的两种方式
方式一
from threading import Thread
import time def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone') if __name__ == '__main__': t1 = Thread(target=task,args=('张三',)) # args的参数一定要是元组
t1.start()
print('===主线程') # 线程是没有主次之分的.
方式二
from threading import Thread
import time class MyThread(Thread):
def __init__(self,name,l1,s1):
super().__init__()
self.name = name
self.l1 = l1
self.s1 = s1
def run(self):
print(f'{self.name} is running')
time.sleep(1)
print(f'{self.name} is gone') if __name__ == '__main__':
t1 = MyThread('张三', [1,2,3], '180')
t1.start()
print('=====主线程')
4. 线程、进程对比代码验证
开启速度对比
# 多进程
from threading import Thread
from multiprocessing import Process
import os def work():
print('hello') if __name__ == '__main__':
t=Process(target=work)
t.start()
print('主线程/主进程') # 多线程
from threading import Thread
import time def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone') if __name__ == '__main__':
t1 = Thread(target=task,args=('张三',))
t1.start()
print('===主线程') # 结论:
# 多进程是先打印的'主线程/主进程',多线程是先打印的'张三 is running',所以得出线程的开启速度比进程快
对比pid
# 多进程
from multiprocessing import Process
import time
import os def task(name):
print(f'子进程: {os.getpid()}')
print(f'主进程: {os.getppid()}') if __name__ == '__main__':
p1 = Process(target=task,args=('张三',)) # 创建一个进程对象
p2 = Process(target=task,args=('李四',)) # 创建一个进程对象
p1.start()
p2.start()
print(f'==主{os.getpid()}') # 多线程
from threading import Thread
import os def task():
print(os.getpid()) if __name__ == '__main__':
t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
print(f'===主线程{os.getpid()}') # 结论:
# 线程没有pid,进程才有pid
共享数据的对比,同一个进程内线程共享内部数据
from threading import Thread
import os x = 3
def task():
global x
x = 100 if __name__ == '__main__':
t1 = Thread(target=task)
t1.start()
t1.join()
print(f'===主线程{x}') # 同一进程内的资源数据对于这个进程内的多个线程来说是共享的.
5. 线程的其他方法
代码示例:
from threading import Thread
from threading import currentThread
from threading import enumerate
from threading import activeCount
import os
import time def task():
print(currentThread()) # 获取当前线程对象
time.sleep(1)
print('666') if __name__ == '__main__':
t1 = Thread(target=task,name='线程1') # name 设置线程名
t2 = Thread(target=task,name='线程2')
t1.start()
t2.start()
time.sleep(2)
print(t1.isAlive()) # 判断线程是否活着
print(t1.getName()) # 获取线程名
t1.setName('子线程-1') # 设置线程的名称
print(t1.name) # 获取线程名 *** # threading方法
print(currentThread()) # 获取当前线程的对象
print(enumerate()) # 返回一个列表,包含所有的线程对象
print(activeCount()) # 获取当前线程存活个数 ***
print(f'===主线程{os.getpid()}')
6. 线程join
join: 阻塞 告知主线程要等待我子线程执行完毕之后再执行主线程
代码示例:
from threading import Thread
import time def task(name):
print(f'{name} is running')
time.sleep(1)
print(f'{name} is gone') if __name__ == '__main__':
start_time = time.time()
t1 = Thread(target=task,args=('张三',))
t2 = Thread(target=task,args=('李四',))
t3 = Thread(target=task,args=('王五',)) t1.start()
t1.join()
t2.start()
t2.join()
t3.start()
t3.join() print(f'===主线程{time.time() - start_time}') # 线程是没有主次之分的.
7. 守护线程
守护线程:等待非守护子线程以及主线程结束之后,结束.
代码示例:
示例一:简单使用守护线程
from threading import Thread
import time def sayhi(name):
print('你好!')
time.sleep(2)
print('%s say hello' %name) if __name__ == '__main__':
t = Thread(target=sayhi,args=('张三',))
# 方式1:
t.setDaemon(True) # 必须在t.start()之前设置
# 方式2:
t.daemon = True
t.start()
print('主线程')示例二:守护线程在非守护线程结束前先结束
from threading import Thread
import time def foo():
print(123) # 第1步
time.sleep(1)
print("end123") # 第4步 def bar():
print(456) # 第2步
time.sleep(3)
print("end456") # 第5步 t1=Thread(target=foo)
t2=Thread(target=bar) t1.daemon=True
t1.start()
t2.start()
print("---main---") # 第3步 # 结果:
# 123
# 456
# ---main---
# end123
# end456示例三:守护线程在非守护线程结束之后结束
from threading import Thread
import time def foo():
print(123) # 第1步
time.sleep(3)
print("end123") def bar():
print(456) # 第2步
time.sleep(1)
print("end456") # 第4步 t1=Thread(target=foo)
t2=Thread(target=bar) t1.daemon=True
t1.start()
t2.start()
print("main-------") # 第3步 # 结果:
# 123
# 456
# main-------
# end456
8. 线程互斥锁
多个任务公抢一个数据,保证数据的安全的目的,要让其串行
代码示例
from threading import Thread
from threading import Lock
import time
import random x = 100
def task(lock):
lock.acquire()
global x
temp = x
time.sleep(0.01)
temp = temp - 1
x = temp
lock.release() if __name__ == '__main__':
mutex = Lock()
l1 = []
for i in range(100):
t = Thread(target=task,args=(mutex,))
l1.append(t)
t.start() for i in l1:
i.join()
print(f'主线程{x}')
Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁的更多相关文章
- Python之queue模块以及生产消费者模型
队列 队列类似于一条管道,元素先进先出,进put(arg),取get() 有一点需要注意的是:队列都是在内存中操作,进程退出,队列清空,另外,队列也是一个阻塞的形态. 队列分类 队列有很多中,但都依赖 ...
- Python - Asyncio模块实现的生产消费者模型
[原创]转载请注明作者Johnthegreat和本文链接 在设计模式中,生产消费者模型占有非常重要的地位,这个模型在现实世界中也有很多有意思的对应场景,比如做包子的人和吃包子的人,当两者速度不匹配时, ...
- python并发编程之多线程基础知识点
1.线程理论知识 概念:指的是一条流水线的工作过程的总称,是一个抽象的概念,是CPU基本执行单位. 进程和线程之间的区别: 1. 进程仅仅是一个资源单位,其中包含程序运行所需的资源,而线程就相当于车间 ...
- 29 python 并发编程之多线程理论
一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资源整合 ...
- 三 python并发编程之多线程-理论
一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资源整合 ...
- python并发编程之多线程理论部分
阅读目录 一 什么是线程 二 线程的创建开销小 三 线程与进程的区别 四 为何要用多线程 五 多线程的应用举例 六 经典的线程模型(了解) 七 POSIX线程(了解) 八 在用户空间实现的线程(了解) ...
- 35、python并发编程之多线程(理论篇)
一 什么是线程 二 线程的创建开销小 三 线程与进程的区别 四 为何要用多线程 五 多线程的应用举例 六 经典的线程模型(了解) 七 POSIX线程(了解) 八 在用户空间实现的线程(了解) 九 在内 ...
- 【Java并发编程】:生产者—消费者模型
生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据“姓 ...
- python 并发编程之多线程
一.线程理论 1.什么是线程 多线程(即多个控制线程)的概念是,在一个进程中存在多个线程,多个线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源. 所以,进程只是用来把资 ...
随机推荐
- Idea 添加注释:类注释、方法注释(可获取参数)
原文链接:https://blog.csdn.net/liqing0013/article/details/84104419 Idea 添加注释:类注释.方法注释 类注释 File–Setting–E ...
- php读取富文本处理html标签问题
thinkphp的一项配置会将富文本编辑器的内容中的html标签进行转义处理 'DEFAULT_FILTER' => 'htmlspecialchars', // 默认参数过滤方法使用htmls ...
- MySQL的使用方法和视图、索引、以及存储过程的一些简单方法
一,基本概念 1, 常用的两种引擎: (1) InnoDB a,支持ACID,简单地说就是支持事务完整性.一致性: b,支持行锁,以及类似ORACLE的一 ...
- Java学习笔记6(集合类)
集合类 集合按照其存储结构可以分为两大类,即单列集合Collection和双列集合Map. Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,有List和Set两个重要子接口 ...
- EM(最大期望)算法推导、GMM的应用与代码实现
EM算法是一种迭代算法,用于含有隐变量的概率模型参数的极大似然估计. 使用EM算法的原因 首先举李航老师<统计学习方法>中的例子来说明为什么要用EM算法估计含有隐变量的概率模型参数. 假设 ...
- 在Java虚拟机上班是一种怎样的体验?
228 人赞同了该回答 利益相关,匿了! JVM公司里面线程众多,派系林立,尤其是执行引擎那波人,因为是核心部门,经常diss别的部门. 428 人赞同了该回答 不请自来. 其实在JVM工作没有你们想 ...
- java scoket Blocking 阻塞IO socket通信三
在NIO同步非阻塞的场景中和原来同步阻塞最大的却别就是引入了上面的Buffer对象,现在我们来学校上面的BUffer对象 我们来看看程序的代码: package bhz.nio.test; impor ...
- RabbitMQ:三、进阶
保证消息的安全 持久化 交换器持久化:声明交换器时指定持久化 队列持久化:声明队列时指定持久化 消息持久化:发送消息时指定持久化 一般队列和消息持久化要同时声明,此外消息假如进了交换器却找不到队列,也 ...
- Java的前生今世
Java作为一门编程语言,自诞生以来已经流行了20多年,在学习它之前,我们有必要先了解一下它的历史,了解它是如何一步步发展到今天这个样子. 孕育 上世纪90年代,硬件领域出现了单片式计算机系统,比如电 ...
- bugku 一个神奇的登录框
一个登录界面,填个admin,123试试,提示try again 抓包看看. 在admin后加个’提示try again 看来是被过滤了,试试” 报错了,加上# 报错没有了,说明存在注入点. 先来判断 ...