python基础之并发编程(一)
作者:宠乖仪 发布时间:2021-01-10 08:56:15
目录
一、进程(Process)
二、线程(Thread)
三、并发编程解决方案:
四、多线程实现 (两种)
1、第一种 函数方法
2、第二种 类方法包装
五、守护线程与子线程
1、线程在分法有:
2、守护线程
六、锁
七、死锁
八、信号量(Semaphore)
九、事件(Event)
十、线程通信-队列
1使用的队列的好处:
2Queue模块中的常用方法:
十一、生产者和消费者模式
总结
一、进程(Process)
是一个具有一定独立功能的程序关于某个数据集合的一次运行活动
二、线程(Thread)
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进 程中的实际运作单位。
三、并发编程解决方案:
1、多任务的实现有 3 种方式:
多进程模式;
多线程模式;
多进程+多线程模式
四、多线程实现 (两种)
1、第一种 函数方法
# 方法包装-启动多线程
from threading import Thread
from time import sleep, time
def func1(name):
print("Threading:{} start".format(name))
sleep(3)
print("Threading:{} end".format(name))
if __name__ == '__main__':
# 开始时间
start = time()
# 创建线程列表
t_list = []
# 循环创建线程
for i in range(10):
t = Thread(target=func1, args=('t{}'.format(i),))
t.start()
t_list.append(t)
# 等待线程结束
for t in t_list:
t.join()
# 计算使用时间
end = time() - start
print(end)
2、第二种 类方法包装
# 类包装-启动多线程
from threading import Thread
from time import sleep, time
class MyThread(Thread):
def __init__(self,name):
Thread.__init__(self)
self.name =name
def run(self):
print("Threading:{} start".format(self.name))
sleep(3)
print("Threading:{} end".format(self.name))
if __name__ == '__main__':
# 开始时间
start = time()
# 创建线程列表
t_list = []
# 循环创建线程
for i in range(10):
t = MyThread('t{}'.format(i))
t.start()
t_list.append(t)
# 等待线程结束
for t in t_list:
t.join()
# 计算使用时间
end = time() - start
print(end)
注意:
主线程不会等待子线程运行结束,如果需要等待可使用 join()方法不要启动线程后立即 join(),很容易造成串行运行,导致并发失效
五、守护线程与子线程
1、线程在分法有:
主线程:程序的本身
子线程:在程序另开起的线程
2、守护线程
主要的特征是它的生命周期。主线程死亡,它也就随之 死亡
# 类包装-启动多线程
from threading import Thread
from time import sleep, time
class MyThread(Thread):
def __init__(self,name):
Thread.__init__(self)
self.name =name
def run(self):
print("Threading:{} start".format(self.name))
sleep(3)
print("Threading:{} end".format(self.name))
if __name__ == '__main__':
# 开始时间
start = time()
# 循环创建线程
for i in range(10):
t = MyThread('t{}'.format(i))
t.setDaemon(True)
t.start()
# 计算使用时间
end = time() - start
print(end)
六、锁
from threading import Thread
def func1(name):
print('Threading:{} start'.format(name))
global num
for i in range(50000000): # 有问题
#for i in range(5000): # 无问题
num += 1
print('Threading:{} end num={}'.format(name, num))
if __name__ == '__main__':
num =0
# 创建线程列表
t_list = []
# 循环创建线程
for i in range(5):
t = Thread(target=func1, args=('t{}'.format(i),))
t.start()
t_list.append(t)
# 等待线程结束
for t in t_list:
t.join()
Python 使用线程的时候,会定时释放 GIL 锁,这时会 sleep,所以才会出现上面的问题。 面对这个问题,如果要解决此问题,我们可以使用 Lock 锁解决此问题( 加锁的目的是:保证数据安全)
from threading import Thread,Lock
def func1(name):
# 获取锁
lock.acquire()
with lock:
global count
for i in range(100000):
count += 1
# 释放锁
lock.release()
if __name__ == "__main__":
count = 0
t_list = []
# 创建锁对象
lock = Lock()
for i in range(10):
t = Thread(target=func1,args=(f't{i+1}',))
t.start()
t_list.append(t)
for t in t_list:
t.join()
print(count)
七、死锁
from threading import Thread, Lock #Lock 锁 同步锁 互斥锁
from time import sleep
def fun1():
lock1.acquire()
print('fun1 拿到键盘')
sleep(2)
lock2.acquire()
print('fun1 拿到鼠标')
lock2.release()
print('fun1 释放鼠标')
lock1.release()
print('fun1 释放键盘')
def fun2():
lock2.acquire()
print('fun2 拿到鼠标')
lock1.acquire()
print('fun2 拿到键盘')
lock1.release()
print('fun2 释放键盘')
lock2.release()
print('fun2 释放鼠标')
if __name__ == '__main__':
lock1 = Lock()
lock2 = Lock()
t1 = Thread(target=fun1)
t2 = Thread(target=fun2)
t1.start()
t2.start()
from threading import RLock
'''
Lock 锁 同步锁 互斥锁
RLock 递归锁
'''
def func1():
lock.acquire()
print('func1获取锁')
func2()
lock.release()
print('func1释放锁')
def func2():
lock.acquire()
print('func2获取锁')
lock.release()
print('func2释放锁')
def func3():
func1()
func2()
if __name__ == "__main__":
#lock = Lock() 会产生错误
lock = RLock()
func3()
八、信号量(Semaphore)
我们都知道在加锁的情况下,程序就变成了串行,也就是单线程,而有时,我们在不用考 虑数据安全时,为了避免业务开启过多的线程时。我们就可以通过信号量(Semaphore)来 设置指定个数的线程。(比如:电梯每次只能承载三个人,那么同时只能有三个人乘坐,其他人只能等别人做完才能乘坐)
from time import sleep
from threading import Thread
from threading import BoundedSemaphore
def index(num):
lock.acquire()
print(f'第{num}个人乘坐!!')
sleep(2)
lock.release()
if __name__ == "__main__":
lock = BoundedSemaphore(3)
for i in range(10):
t = Thread(target=index,args=(f'{i+1}',))
t.start()
九、事件(Event)
Event()可以创建一个事件管理标志,该标志(event)默认为 False,event 对象主要有 四种方法可以调用:
1、 event.wait(timeout=None):
调用该方法的线程会被阻塞,如果设置了 timeout 参数,超时后,线程会停止阻塞继续执行;
2、event.set():
将 event 的标志设置为 True,调用 wait 方法的所有线程将被唤 醒;
3、event.clear():
将 event 的标志设置为 False,调用 wait 方法的所有线程将被 阻塞;
4、event.is_set():
判断 event 的标志是否为 True。
十、线程通信-队列
线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并 行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不 会出现数据污染等意外情况
1使用的队列的好处:
1. 安全
2. 解耦
3. 提高效率
2Queue模块中的常用方法:
Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步
Queue.qsize()
返回队列的大小Queue.empty()
如果队列为空,返回True,反之FalseQueue.full()
如果队列满了,返回True,反之FalseQueue.full
与maxsize
大小对应Queue.get([block[, timeout]])
获取队列,timeout等待时间Queue.get_nowait()
相当Queue.get(False)
Queue.put(item)
写入队列,timeout等待时间Queue.put_nowait(item
) 相当Queue.put(item, False)Queue.task_done()
在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号Queue.join()
实际上意味着等到队列为空,再执行别的操作
十一、生产者和消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者 彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费 者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列 就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
from threading import Thread
from queue import Queue
from time import sleep
def producer():
num = 1
while True:
print(f'生产了{num}号皮卡丘')
qe.put(f'{num}号皮卡丘')
num += 1
sleep(1)
def consumer():
print('购买了{}'.format(qe.get()))
sleep(2)
if __name__ == "__main__":
# 共享数据的容器
qe= Queue(maxsize=5)
# 创建生产者线程
t1 = Thread(target = producer)
# 创建消费者线程
t2 = Thread(target = consumer)
# 创建消费者线程
t3 = Thread(target = consumer)
# 开始工作
t1.start()
t2.start()
t3.start()
来源:https://blog.csdn.net/qq_53582111/article/details/120822344


猜你喜欢
- 我们提倡无论何时都尽可能地使用CSS,这样我们更容易取得成功.现在浏览器对CSS的支持已经非常好,肯定足以让你用来控制你的网页布局与排版.但
- [javascript] var forimg = function (foritem, hoverStop, defaultf
- Anaconda 是一个基于 Python 的数据处理和科学计算平台,它已经内置了许多非常有用的第三方库,装上Anaconda,就相当于把
- 本文实例讲述了Python实现连接两个无规则列表后删除重复元素并升序排序的方法。分享给大家供大家参考,具体如下:# -*- coding:u
- 前言本文主要给大家介绍了关于mysql语句插入含单引号或反斜杠值的相关内容,下面话不多说了,来一起看看详细的介绍吧比如说有个表,它的结构是这
- 1、使用专用网站获取的是公网IP网址:http://myip.ipip.net代码:import requestsres = request
- 前言&最近因为一些原因,没有更博客,昨天老师布置了一个作业,用vue实现增删改查功能,想想这也不难,就做一下试试吧。因为自己写的样式
- 然而这里不打算对某种存储引擎的实现细节进行描述,也不打算介绍各种存储引擎的优缺点,只是描述一下mysql如何处理binlog,并澄清几个容易
- 理解SQL Server对于内存的管理是对于SQL Server问题处理和性能调优的基本,本篇文章讲述
- 在做数据分析或者统计的时候,经常需要进行数据正态性的检验,因为很多假设都是基于正态分布的基础之上的,例如:T检验。在Python中,主要有以
- 大家好,我们经常会有这样的需求。比如下图我们需要把同一个省份的合并起来,如下图的效果如何实现呢,这是原有的df直观的操作是这样的:df.to
- IE6下浮出层常会需要增加一个iframe来解决浮出层被Obj穿透的问题,这个是目前最有效的方案,不过这个方案本身有个缺陷,就是iframe
- 一般情况下TextArea区输入的文字数量是没有限制的,但是我们可以通过javascript限制表单的文字字数。如下javascript代码
- 介绍我编写了一个快速且带有斑点的python脚本,以可视化nmap和masscan的结果。它通过解析来自扫描的XML日志并生成所扫描IP范围
- 而每次查询分析器寻找路径时,并不会每一次都去统计索引中包含的行数,值的范围等,而是根据一定条件创建和更新这些信息后保存到数据库中,这也就是所
- 当一个应用的数据量大的时候,我们用单表和单库来存储会严重影响操作速度,如mysql的myisam存储,我们经过测试,200w以下的时候,my
- 小整数/* interpreter state */#define _PY_NSMALLPOSINTS &nbs
- 很多网站需要将好的会员号留着,或用于日后的盈利。实现方法不是本文讨论范围,本文仅列出用于检测靓号类型的一些正则。靓号检测:主要可以检测连号(
- 1、去除一个数组中的重复元素:使用grep函数代码片段: 代码:my @array = ( 'a', 'b'
- 本文实例为大家分享了Python+OpenCV实现图像的全景拼接的具体代码,供大家参考,具体内容如下环境:python3.5.2 + ope