线程
线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程就是车间中的工人,实际干活的也是工人,真正执行程序的还是线程。
单线程
程序中的代码按照计算机的线程去逐行执行
单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。
import time
# print("{:.2%}".format(0.3))
def upload():
print("开始上传。。。")
for i in range(1,5):
print(f"上传了{'{:.2%}'.format(i / 4)}")
time.sleep(1)
print("上传完毕。。。")
def download():
print("开始下载.......")
for i in range(1,5):
print(f"下载了{'{:.2%}'.format(i / 4)}")
time.sleep(1)
print("下载完毕.......")
upload()
download()
多线程
多线程类似于同时执行多个不同程序
import time
import threading
def upload():
print("开始上传.......")
for i in range(1, 5):
print(f"上传了{'{:.2%}'.format(i / 4)}")
time.sleep(1)
print("上传结束.......")
def download():
print("开始下载.......")
for i in range(1, 5):
print(f"下载了{'{:.2%}'.format(i / 4)}")
time.sleep(1)
print("下载完毕.......")
def main():
upload_thread=threading.Thread(target=upload)
down_thread=threading.Thread(target=download)
upload_thread.start()
down_thread.start()
if __name__ == '__main__':
main()
多线程的优点
使用线程可以把占据长时间的程序中的任务放到后台去处理。
用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
程序的运行速度可能加快
在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
多线程的特点
线程执行代码的封装
通过使用threading模块能够完成多任务的程序开发,为了让每个线程的封装性更完美所以使用threading模块时,往往会自定义一个新的子类class,只要继承threading.Thread即可实现
多线程共享全局变量
在一个函数中对全局变量进行修改的时候,到底是否需要看是否对全局变量的执行进行了引用修改,如果修改了引用,也就是说让全局变量指向了一个新的地方,如果仅修改了引用的数据,此时不用担心变量被分化
同步
同步指的是协同步调,按预定的先后次序进行运行
线程通过或者进程同步,可以列几位进程或线程A和B一块配合,A执行到一定程度需要依靠B的某个结果,如果B还没有执行完得出结果,那么A就需要停下来等到B运行,反之也是如此
互斥锁
当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程的同步能够保证多个线程安全访问竞争资源,最简单的同步机制就是引入互斥锁
互斥锁为资源引入了一个状态:锁定/非锁定
某个线程需要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能修改,直到该线程释放资源,将资源的状态变成“非锁定”,其他线程才能够再次锁定该资源,互斥锁保证了每次只有一个线程进行写入工作,从而保证了多线程情况下的数据正确
threading模块中定义了Lock锁,可以方便的处理锁定
1.先创建互斥锁
mutex=threading.Lock()
2.锁定资源
mutex.acquire()
3.解锁资源
mutex.release()
注意:在使用互斥锁的同时,锁定的资源越少越好
死锁
在线程间共享多个资源的时候,如果每个线程分别占有一部分资源,并且同时等待对方的资源,就会造成死锁
如何避免死锁:
- 程序设计时要尽量避免(银行家算法)
- 添加超时时间