Python并发复习1 - 多线程
一、基本概念
程序: 指令集,静态,
进程: 当程序运行时,会创建进程,是操作系统资源分配的基本单位
线程: 进程的基本执行单元,每个进程至少包含一个线程,是任务调度和执行的基本单位
> 进程和线程之间的关系:
① 一个线程只属于一个进程
② 一个进程可以包含多个线程,只有一个主线程
> 进程和线程资源对比
① 进程具有独立的空间和系统资源
② 线程不具有独立的空间和系统资源
③ 同一个进程下的多个线程共享该进程的空间和系统资源
④ 局部变量不共享
> 多线程中对于贡献资源修改的问题
--- 多线程的同步问题、 线程不安全、通过同步解决
二、 多线程
1.需要清楚的一点
单核CPU: 宏观并行,微观实际上是串行 - 并发
多核CPU: 微观本质并行
2.应用场合:
① 计算密集型 --- 不适合单核CPU多线程 --- 数值计算
② I/O密集型 --- 适合单核CPU多线程 --- 频繁读写
3.优点:
速度快
4.缺点:
(1) 线程本身也是程序,线程越多,占用的内存越多;
(2) 多线程的调用需要协调管理,CPU对线程的跟踪需要消耗内存;
(3) CPU多线程的切换需要消耗内存
(4) 多线程之间对共享资源问题,需要解决数据的一致性
三、 线程的创建
三种方式:
(1) threading模块
--- 通过指定target(函数名)和args(函数参数)
(2) 使用Thread类,重写run方法
(3) 使用线程池
3.1 threading模块
import threading
import time
def misson(*args):
for i in range(args[1]):
print(i)
time.sleep(1)
# 创建线程对象,参数必须使用元组传递
t = threading.Thread(target = mission, args = args)
# 激活线程(排队),等待CPU分配时间片来执行
t.start()
t.start()
3.2. 使用Thread类,重写run方法
--- 适用于需要创建很多个执行方法相同的线程对象时,用类方法
class My_Thread(threading.Thread):
def __init__(self, n1):
self.n1 = n1
super().__init__()
# run方法是真正执行函数认为的方法
def run(self):
for i in range(self.end):
print(i)
t1 = My_Thread()
t1.start(10)
3.3 线程池
线程池的使用threadpool较少,使用concurrent.futures下的 ThreadPoolExecutor 线程池
from concurrent.futures import ThreadPoolExecutor
import time def sayhello(a):
print("hello: " + a)
time.sleep(2) def main():
seed = ["a", "b", "c"] # 第一种方法submit
with ThreadPoolExecutor(3) as executor:
for each in seed:
executor.submit(sayhello, each) # 第二种方法map
with ThreadPoolExecutor(3) as executor1:
executor1.map(sayhello, seed) if __name__ == '__main__':
main()
四、 线程的生命周期
(1) 新建 --- 创建线程对象,没有执行能力
(2) 就绪 --- 调用start方法,把执行权利交给CPU
(3) 运行 --- 执行线程任务,获得CPU时间片在一个线程运行时,可能将时间片分配给其他线程
(4) 阻塞 --- 处于等待过程,CPU不给阻塞状态分配时间片
(5) 死亡 --- run方法执行完毕或者抛出没有捕获的异常
五、线程的同步
--- 在同一个进程下,各个线程共享资源引起不安全,即对成员变量的操作进行共享
1. 抢票问题 - 锁
import time
import threading ticket = 100 def buy_ticket():
global ticket
while ticket:
t = threading.current_thread()
print(f'{t.name}{ticket}')
time.sleep(0.5)
ticket -= 1 if __name__ == '__main__':
t1 = threading.Thread(target=buy_ticket)
t1.name = '张三' # 设定线程名字
t1.start()
t2 = threading.Thread(target=buy_ticket)
t2.name = '张四'
t2.start()
t3 = threading.Thread(target=buy_ticket)
t3.name = '张五'
t3.start()
运行结果如下,会出现重复的抢票,即多个线程获得同一个变量:

解决办法:
使用线程锁, 即在同一时间内,一个共享资源只能被一个线程访问
加锁 --- threading.Lock()
抢锁 --- lock.acquare()
解锁 --- lock.release()
import time
import threading lock = threading.Lock()
ticket = 100
def buy_ticket():
global ticket
while True:
try:
lock.acquire()
if ticket > 0:
t = threading.current_thread()
time.sleep(0.2)
print(f'{t.name}抢到了第{ticket}张票')
ticket -= 1
else:
break
finally:
lock.release() t1=threading.Thread(target=buy_ticket)
t1.name="张三"
t2=threading.Thread(target=buy_ticket)
t2.name="李四"
t3=threading.Thread(target=buy_ticket)
t3.name="王五" t1.start()
t2.start()
t3.start()
2. 生产者消费者模型
(1) 消费者一直消费,商品=0,等待生产 --- wait
(2) 生产者隔一段时间看一次,如果小于3,开始生产 --- 耗费CPU
(3) 只要消费者消费了产品,通知生产者生产商品 --- notify
六、多进程
1. 进程创建
(1)使用multiprocessing.Process(target=函数名)
(2)继承Process重写run
2.
进程操作
Os.getpid # 得到本身进程id
Os.getppid # 得到父进程id
Fork:复制进程,只能在linux下使用
其他方法同线程
3.
进程队列
进程优于线程:
不存在资源共享问题,没有同步锁,也没有死锁
多进程需要处理资源共享问题,使用队列序列化处理(进程队列已经处理好)
Python并发复习1 - 多线程的更多相关文章
- Python并发复习2 - 多线程模块threading
一.多线程的调用 threading 模块建立在thread 模块之上.thread模块以低级.原始的方式来处理和控制线程,而threading 模块通过对thread进行二次封装, 提供了更方便的a ...
- Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁
Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...
- python并发编程之多线程基础知识点
1.线程理论知识 概念:指的是一条流水线的工作过程的总称,是一个抽象的概念,是CPU基本执行单位. 进程和线程之间的区别: 1. 进程仅仅是一个资源单位,其中包含程序运行所需的资源,而线程就相当于车间 ...
- Python并发编程之多线程使用
目录 一 开启线程的两种方式 二 在一个进程下开启多个线程与在一个进程下开启多个子进程的区别 三 练习 四 线程相关的其他方法 五 守护线程 六 Python GIL(Global Interpret ...
- python并发编程之多线程1
一多线程的概念介绍 threading模块介绍 threading模块和multiprocessing模块在使用层面,有很大的相似性. 二.开启多线程的两种方式 1.创建线程的开销比创建进程的开销小, ...
- python并发编程之多线程2------------死锁与递归锁,信号量等
一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统 ...
- Python并发复习3 - 多进程模块 multiprocessing
python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程.Python提供了非常好用的多进程包multiprocessing,只需要定 ...
- python 并发编程之多线程
一.线程理论 1.什么是线程 多线程(即多个控制线程)的概念是,在一个进程中存在多个线程,多个线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源. 所以,进程只是用来把资 ...
- python并发编程之多线程2---(死锁与递归锁,信号量等)
一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统 ...
随机推荐
- centos 7.3 设置静态IP
注:本文来源:张亮博客 的 <centos 7.3 设置静态IP或ping 报name or service not known> 首先把虚拟机配置为桥接模式,然后开启再你打算修改虚拟机 ...
- Confluence 6 查看站点状态
请注意,有关站点的活动信息在默认情况下是禁用的.请查看下面的说明. 如果这个插件被启用的话,有关站点的全局活动状态将会在你的 Confluence 站点中显示出来.显示的数据包括: 在给定的时间内有多 ...
- Confluence 6 数据库表和参考
扩展下面的链接来显示主要的表格和每一个表格的外键. 单击这里来显示/隐藏表格... AO_9412A1_AOUSER ID AO_9412A1_USER_APP_LINK USER_ID fk_ao ...
- Confluence 6 PostgreSQL 问题解决
如果 Confluence 提示没有 class 文件,你可能将你的 JDBC 驱动放置到了错误的文件夹. 如果你不能从你从 Confluence 中连接到 PostgreSQL ,并且这 2 个服务 ...
- Redis事务概念
redis事务与监控 Author:SimpleWu GitHub-redis 在redis中它的事务与批处理非常相似 Redis中的事务(transaction)是一组命令的集合.事务同命令一样都是 ...
- Django 之缓存
一.缓存 由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcac ...
- django rest framework(4)
目录 一.分页 二.视图 三.路由 四.渲染器 一.分页 试问如果当数据量特别大的时候,你是怎么解决分页的? 方式a.记录当前访问页数的数据id 方式b.最多显示120页等 方式c.只显示上一页,下一 ...
- 【python】正则替换
正则替换可以使用函数 例如:替换字符串中所有#1.2.3.4#格式中的数字为0 import re def replace(x): def _replace(matched): m = matched ...
- samba 二进制包 tar.gz 安装
一.下载 sudo wget https://download.samba.org/pub/samba/stable/samba-4.8.10.tar.gz 二.解压 sudu tar -xvzf s ...
- uva11865 二分流量+最小生成树
uva好题真多 本题用二分法找flow,把流量小于flow的全部筛掉,剩下的边建立最小树形图,如果权值大于c或者不能建图,那么修改二分边界 上代码,觉得最小树形图的代码很优美 /* 题意:给定n个点, ...