102
多任务 同一时间多个任务执行 多个进程
操作系统可以同事运行多个任务 多核的cpu已经非常的普及
单核的cpu也可以执行多个任务
#!/usr/bin/python
# Write Python 3 code in this online editor and run it.
print("Hello, Wo rld!");
#线程的基本使用
#使用threading模块创建线程
'''子线程创建步骤
1 导入模块 threading
2 使用threading.thread()创建对象 (子线程对象)
3 指定子线程执行的分支
4 启动子线程 线程对象.start()
'''
import time
import threading
def saysorry():
print("sorry")
time.sleep(0.5)
if __name__ == "__main__":
for i in range(5):
#2 使用threading.thread()创建对象 (子线程对象)
# threading.Thread(target = 函数名)
th_obj = threading.Thread(target=saysorry)\
#saysorry() #调用函数 单线程方式
th_obj.start()
#主线程等子线程结束才结束
print("111111111111111111")#子线程与主线程同时执行
-----------------------------------------------------------------------------------------------
import time
import threading
def sing():
for i in range(5):
print ("sing")
def dance():
for i in range(5):
print ("dance")
if __name__ == "__main__":
for i in range(5):
#2 使用threading.thread()创建对象 (子线程对象)
# threading.Thread(target = 函数名)
th_obj_sing = threading.Thread(target=sing)
th_obj_dance = threading.Thread(target=dance)
th_obj_sing.start()
th_obj_dance.start()
#主线程等子线程结束才结束
print("111111111111111111")#子线程与主线程同时执行
主线程的作用是创建子线程
等子线程结束才关闭
子线程 程序的一个分支
导入模块 import threading
创建对象 threading.Thread(target=funcname)
启动子线程对象 线程对象.start()
----------------------------------------------------------------------------------
线程的数量
如何查看线程的数量
threading.enumerate()获取当前所有活跃的线程数量
args=(参数1,参数2,。。。。)
元祖与字典混合时 元祖后面加上一个逗号
线程是被系统独立调度和分派的最小系统
无法控制线程调度程序 但可以通过别的方式来影响线程调度的方式
说明:多线程程序的执行顺序是不确定的,当执行到sleep语句的时候,线程被阻塞blocked
,到sleep结束后,线程进入就绪runnable状态,等待调度 而线程调度将自行选择一个线程执行。
线程参数
元祖
threading.tread(targer=xxxx,agrs=(param1,param2...))
字典
threading.tread(targer=xxxx,kwargs=(参数1:param1,参数2:param2...))
混合
threading.tread(targer=xxxx,agrs=(param1,param2,...,),kwargs=(参数1:param1,参数2:param
线程的顺序
线程执行无法 由cpu自己算法调度 程序员无法控制
------------------------------------------------------------------------------------------
线程的守护 守护线程
能够使用setDaemon 设置子线程守护主线程
子线程在主线程的时候自动退出
import time
import threading
def work1():
for i in range(10):
print("正在执行work1.。。。。")
time.sleep(0.5)
if __name__=="__main__":
#创建线程对象
thread_work= threading.Thread(target=work1)
#线程守护 子线程守护主线程
#setDaemon(True) 表示子线程守护了主线程 主线程结束后 子线程也结束
thread_work.setDaemon(True)
thread_work.start()
#睡眠2秒
time.sleep(2)
print("over !!!!!!")
#让程序退出 主线程主动结束
exit() #如果没有此行命令 thread_work.setDaemon(True) 主线程结束 但子线程也没有结束
---------------------------------------------------------------------------------------------
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。
并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。
所以我认为它们最关键的点就是:是否是『同时』。
做并发编程之前,必须首先理解什么是并发,什么是并行,什么是并发编程,什么是并行编程。
并发(concurrency)和并行(parallellism)是:
解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
解释三:并行是在多台处理器上同时处理多个任务,如hadoop分布式集群。并发是在一台处理器上“同时”处理多个任务。
当一个计算机 多个任务的时候其实就是让操作系统轮流让各个任务交替执行
雨露均沾
2.8G 2.8亿次
并发 指的是任务数大于cpu核数
并行 任务数小于cpu核数 即任务一块执行
并发:任务数大于cpu核心数
并行:任务数小于或等于cpu的核心数
---------------------------------------------------------------------------------------
自定义线程类
通过集成threading.Thread 可以实现自定义线程
方法:
让自定义类继承 threading.thread类
重写父类(threading.Thread) run 方法
通过创建子类对象 让子类对象.start()就可以启动子线程
import time
import threading
'''
def run():
pass
def start():
'''
#自定义类名
class mythread11(threading.Thread):
def __init__(self,num):
#必须先去调用父类的init方法 此处采用的方法是 super()
super().__init__()
self.num = num
#重写父类的run方法
def run(self):
for i in range(8): #self.name 线程的名字
#self.name 从父类继承的一个属性
print("正在执行子线程run方法...",i," ",self.name," ",self.num)
time.sleep(0.5)
if __name__=="__main__":
myth = mythread11(10)
myth.start() #调用start 执行run start函数里面执行run函数
print("xxxxxxxxxxx")
'''
导入模块
创建类并且继承threading.Thread
calss mythread(threading.Thread)
重写父类的方法
def run(self)
...
创建对象并且调用.start()
myth = mythread()
mythread.start()
底层原理
Thread类
run方法
start()
start中调用run方法
自定义线程类的init方法问题
子类先通过super调用父类的初始化方法 子类再初始化
def __init__(self,num):
#先调用父类的init方法
super().__init__()
self.num =num
'''
--------------------------------------------------------------------
##多线程共享全局变量
#多线程方法中可以共享全局变量
#函数1对函数的全局变量1的值修改 与此同时函数2中获取全局变量的值
import threading
import time
num =0
def work1():
#申明变量是一个全局变量 否则不可以修改
#num =0
global num
for i in range(10000000):
num +=1 #1、获取num的值 2、num值加1 3、赋值
print("work1 num =",num)
def work2(): #
global num
for i in range(10000000):
num +=1
print("work2 num =",num)
if __name__ == "__main__":
#创建子线程
t1 = threading.Thread(target = work1)
t2 = threading.Thread(target = work2)
#启动线程
t1.start()
#如果让一个线程运行完再运行下一个线程 就可以解决资源竞争 但这样就不存在多线程的含义了
#优先让t1线执行 执行完毕后 t2才可以执行
t1.join()
#t1.join()的缺点 把多线程变成了单线程 影响整体的性能
t2.start()
#多线程之间可以共享变量 存在资源竞争
while len(threading.enumerate())!=1: #等子线程结束后再执行
time.sleep(1)
#在t1和t2线程完毕后 打印 num
print("main-------------",num) ##最后输出的结果小于真实值
##多线程 共享全局变量问题
#导致资源竞争的问题
#加入两个线程函数均对同一个变量进行修改
###一千万加上一千万小于两千万的结果 造成资竞争
------------------------------------------------------------------------------
#同步:多任务
#异步:指的是多个任务之间执行没有先后顺序 可以同时执行 执行的先后顺序不会有影响 存在的多条运行主线
#同步:多任务直接执行的顺序有先后的顺序
#解决线程同时修改全局变量的方式
#线程锁的机制
#A线程获得 g_num的使用权并且加上了机制锁 此时BC线程无法使用G_num,BC必须等到A线程不再使用g_num并且解锁后,才能使用g_num.
#蚂蚁森林种树的机制
#同步 再多任务中 执行有先后的顺序 一个执行完毕 另外一个才可以执行
#异步 在多任务的执行没有先后的顺序 多个任务同时执行
#线程的锁机制 当线程获取资源后 立刻进行锁定 资源使用完毕后再解锁 有效的保证同一时间只有一个线程在使用资源
#---------------------------------------------#
#互斥锁
#利用互斥锁解决资源竞争的问题
'''
三大步骤
创建一把锁
lock1 = threading.Lock()
上锁
lock1.acquire()
解锁
lock1.release()
'''
'''
当多个线程几乎同时修改某一个共享数据的时候 需要进行同步控制
线程同步可以保证几个线程安全访问竞争资源 最简单的同步机制是引入互斥锁
互斥锁为资源引入一个状态 锁定/非锁定
某线程要更改共享数据时,先将其锁定
threading 模块中定义了lock锁 可以方便的处理锁定
创建锁
mutex = threading.lock()
锁定
mutex.acquire()
释放
mutex.release()
如果这个锁之前没有加上锁的 那么acquire不会堵塞的
如果在调用acquire对这个锁之前 他已经被其他线程上了锁 那么此时acquire会堵塞 直到这个锁被解锁为止
使用互斥锁对同一变量进行两百万加法的操作
'''
'''
过程:
创建一把互斥锁
在使用资源之前要锁定
使用完资源后 要解锁释放
'''
##多线程共享全局变量
#多线程方法中可以共享全局变量
#函数1对函数的全局变量1的值修改 与此同时函数2中获取全局变量的值
import threading
import time
num =0
def work1():
#申明变量是一个全局变量 否则不可以修改
#num =0
global num
lock1.acquire()
for i in range(2000000):
###锁定此行 尽可能把资源锁定的最小 锁定紧缺资源
##上锁的时候兼顾性能和原则
#上锁
#lock1.acquire() #可以把锁放在外面 可以解决程序慢的问题 避免频繁的上锁解锁
num +=1 #1、获取num的值 2、num值加1 3、赋值
#lock1.release()
lock1.release()
print("work1 num =",num)
def work2(): #
global num
lock1.acquire()
for i in range(100000):
#上锁 还必须为是同一把锁 才可以互斥
#lock1.acquire()
num +=1
lock1.release()#解锁 他在用的时候别人不可以用
print("work2 num =",num)
if __name__ == "__main__":
# 创建一把互斥锁
lock1= threading.Lock()
#创建子线程
t1 = threading.Thread(target = work1)
t2 = threading.Thread(target = work2)
#启动线程
t1.start()
#如果让一个线程运行完再运行下一个线程 就可以解决资源竞争 但这样就不存在多线程的含义了
#优先让t1线执行 执行完毕后 t2才可以执行
#t1.join()
#t1.join()的缺点 把多线程变成了单线程 影响整体的性能
t2.start()
#多线程之间可以共享变量 存在资源竞争
while len(threading.enumerate())!=1: #等子线程结束后再执行
time.sleep(1)
#在t1和t2线程完毕后 打印 num
print("main-------------",num) ##最后输出的结果小于真实值
##多线程 共享全局变量问题
#导致资源竞争的问题
#加入两个线程函数均对同一个变量进行修改
###一千万加上一千万小于两千万的结果 造成资竞争
--------------------------------------------------------------------------------------
死锁
#!/usr/bin/python
# Write Python 3 code in this online editor and run it.
print("Hello, World!")
#死锁 在线程间共享多个资源的时候 如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁
'''
死锁会造成应用停止
'''
import threading
#定义函数 根据下表获取列表元素值
def get_value(index):
list_data=[11111,21111,311111,411111,5111111]
#上锁
lock1.acquire()
#判断下表是否越界
if index >= len(list_data):
print( "下标越界,",index)
return #越界后等待 5的资源释放
print(list_data[index])
#解锁 越界后 后面一直在等待形成死锁
lock1.release()
if __name__ =="__main__":
#创建一把锁
lock1 = threading.Lock()
#循环创建10个线程
for i in range(10):
t1 = threading.Thread(target=get_value, args=(i,))
t1.start()
#创建10个线程 观察资源的等待状态
'''
互斥锁的步骤
创建一把锁
lock1.threading.Lock()
上锁
lock1.acquire()
解锁
lock1.release()
互斥锁的使用原则 尽可能的减少锁定竞争资源
死锁:在多线程中,两个线程占用一些资源,而且同一时间都在等待对方释放资源,这种状态就是死锁状态
避免:锁使用完毕后 要及时的释放
死锁要满足四个条件 锁的不是线程 而是共享的资源
'''