一、并发和并行
1、多任务
多任务的概念
简单的说,就事操作系统可以同时运行多个任务
CPU与多任务的关系:
单核CPU可不可以多任务?
也可以执行多任务,由于CPU执行代码都是顺序执行的,那么单核CPU是怎么执行多任务的呢?
答案就是操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,在切换到任务3,执行0.01秒.......这样反复下去,表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
真正的并行执行多任务只能在多核CPU上实现,但是由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把多任务轮流调度到每个核心上执行。
2、并发和并行
并发: 指的是任务数多于CPU核数,通过操作系统的各种任务调度算法,实现用多任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起在执行而已)
并行: 指的是任务数小于等于CPU核数,即任务真的在一起执行的
并发
并行
3、同步和异步
同步(同步协调): 是指线程在访问某一资源时,获得了资源的返回结果之后才会执行其他操作,(先做某件事,再做某件事)
异步: 与同步相对,是指线程再访问某一资源时,无论是否取得返回结果,都进行下一步操作;当有了资源返回结果时,系统自会通知线程。
二、线程
问题:
当前有两件事情,做事情1需要5秒,做事情2需要6秒
def func1():
for i in range(5):
print("-----正再做事情1------")
time.sleep(1)
def func2():
for i in range(6):
print("-----正再做事情2------")
time.sleep(1)
单任务
先做事情一
在做事情二
多任务
两个事情同时做
怎么才能同时做呢?
多线程执行
1、Threadting模块介绍
Python的_thread模块是比较底层的模块,Python的threading模块是怼thread模块做了一层包装的,可以更加方便的使用
创建多线程:threading.Thread(target=func1)
参数target指定线程执行的任务(函数)
Thread类提供了以下方法
run() :用以表示线程活动的方法
start() :启动线程活动
join(timeout) :等待子线程的方法,默认等待子线程执行结束
lsAlive() :返回线程是否活动的
getName() :返回线程名
setName() :设置线程名
threading提供的以下方法
threading.current_thread() :返回当前执行的线程
threading.enumerate() :返回正在运行的所有线程(list)
threading.active_count() :返回正在运行的线程数量
2、多线线程实现多任务
利用threading模块实现
import threading
import time
def fun_1():
for i in range(5):
print("线程{}:{}".format(threading.current_thread(), i))
time.sleep(1)
def fun_2():
for i in range(6):
print("线程{}:{}".format(threading.current_thread(), i))
time.sleep(1)
def main():
# 建立线程1 执行函数1
t1 = threading.Thread(target=fun_1, name="th_1")
# 建立线程2 执行函数2
t2 = threading.Thread(target=fun_2, name="th_2")
s_time = time.time()
# fun_1()
# fun_2()
# 设置名字
t1.setName("TH_1")
print(t1.getName())
# 开始
t1.start()
t2.start()
# 查看线程集合,和线程数
print(threading.enumerate())
print(threading.active_count())
# 等待子线程执行完毕
t1.join()
t2.join()
e_time = time.time()
print("时间:", e_time - s_time)
if __name__ == '__main__':
main()
重写run方法实现多线程
线程启动start方法就是运行了run方法
通过继承Thread类,重写run方法,来创见线程
创建线程时不需要在传任务函数
如果任务函数需要参数,需要重写init方法,并返回父类init方法
import threading
import time
import requests
# 计算时间装饰器
def add_time(fun):
def inner(*args):
start_time = time.time()
fun(*args)
end_time = time.time()
print("---------------线程:{},执行时间:{}-----------------".format(threading.current_thread(), end_time - start_time))
return end_time - start_time
return inner
# 重写run方法创建多线程
class RequestThread(threading.Thread):
def __init__(self, url):
self.url = url
super().__init__()
@add_time
def run(self):
for i in range(100):
res = requests.get(self.url).status_code
print("线程{}得执行结果为:{}".format(threading.current_thread(), res))
@add_time
def main():
t_list = [] # 线程列表
# 建立线程
for i in range(10):
t = RequestThread("http://httpbin.org/post")
t_list.append(t)
# 开启线程
for th in t_list:
th.start()
# 等待线程结束
for th in t_list:
th.join()
if __name__ == '__main__':
total_time = main()
print("每个接口平均时间:", total_time / 1000)
3、多线程-共享全局变量
问题:1000000次的bug
两个线程完成对全局变量的2百万次修