Python高级语法——多线程——学习心得笔记
参考博客:
1. 多线程 VS 多进程
-
程序:一堆代码以文本形式存入一个文档
-
进程:程序运行的一个状态
- 包含地址空间,内存,数据栈
- 每个进程有自己独立的运行环境
- 多进程共享数据是一个问题
-
线程
- 一个线程的独立运行片段,一个进程可以有多个线程
- 轻量化的进程
- 一个进程的多个线程共享数据和山下文运行环境
- 共享互斥问题
-
全局解释器(GIL)
- Python代码的执行是由python虚拟机进行控制
- 在主循环中只能有一个控制的线程在执行
-
Python包
- threading 通用的包
- 查看案例28_1单线程耗时长
- 查看案例28_4 多线程耗时短
- 多线程,传递参数案例28_5
28-1
# 多线程实例
# 先写一个单线程
import time
# 单线程实例
def loop1():
# ctime得到当前的时间
print("Start loop 1 at: ", time.ctime())
# 睡眠一定时间,单位是秒
time.sleep(2)
print("End loop 1 at: ", time.ctime())
def loop2():
# ctime得到当前的时间
print("Start loop 2 at: ", time.ctime())
# 睡眠一定时间,单位是秒
time.sleep(3)
print("End loop 2 at: ", time.ctime())
def main():
print("Starting at: ", time.ctime())
loop1()
loop2()
print("All done at: ", time.ctime())
if __name__ == '__main__':
main()
28_4
# 多线程实例
# 28_1.py单线程改写为多线程
# 多线程2,查看结果
# 主程序执行完毕添加一个睡眠时间,等待loop1和loop2执行完
import time
import _thread as thread
# 单线程实例
def loop1():
# ctime得到当前的时间
print("Start loop 1 at: ", time.ctime())
# 睡眠一定时间,单位是秒
time.sleep(2)
print("End loop 1 at: ", time.ctime())
def loop2():
# ctime得到当前的时间
print("Start loop 2 at: ", time.ctime())
# 睡眠一定时间,单位是秒
time.sleep(3)
print("End loop 2 at: ", time.ctime())
def main():
print("Starting at: ", time.ctime())
# 启动一个多线程,()中是放前面函数的参数的
thread.start_new_thread(loop1, ())
# 再启动一个多线程
thread.start_new_thread(loop2, ())
print("All done at: ", time.ctime())
if __name__ == '__main__':
main()
while True:
time.sleep(1)
28_5
# 多线程实例
# 多线程传递参数
import time
import _thread as thread
# 单线程实例
def loop1(in1):
# ctime得到当前的时间
print("Start loop 1 at: ", time.ctime())
print("我是参数", in1)
# 睡眠一定时间,单位是秒
time.sleep(2)
print("End loop 1 at: ", time.ctime())
def loop2(in1, in2):
# ctime得到当前的时间
print("Start loop 2 at: ", time.ctime())
print("我是参数", in1, "和参数", in2)
# 睡眠一定时间,单位是秒
time.sleep(3)
print("End loop 2 at: ", time.ctime())
def main():
print("Starting at: ", time.ctime())
# 启动一个多线程,()中是放前面函数的参数的
# 只有一个参数,后面的逗号要写上,才代表一个元组touple
thread.start_new_thread(loop1, ("Felix", ))
# 再启动一个多线程
thread.start_new_thread(loop2, ("Fang", "Bai"))
time.sleep(6)
print("All done at: ", time.ctime())
if __name__ == '__main__':
main()
- threading的使用
- 直接利用threading.Thread生成Thread实例
- t = threading.Thread(target=xxx, args=(xxx,))
- t.start(): 启动多线程
- t.join(): 等待多线程执行完毕
- 看案例28_6
28-6
- 直接利用threading.Thread生成Thread实例
# 多线程实例
# 多线程传递参数
# 包threading
import time
import threading
# 单线程实例
def loop1(in1):
# ctime得到当前的时间
print("Start loop 1 at: ", time.ctime())
print("我是参数", in1)
# 睡眠一定时间,单位是秒
time.sleep(2)
print("End loop 1 at: ", time.ctime())
def loop2(in1, in2):
# ctime得到当前的时间
print("Start loop 2 at: ", time.ctime())
print("我是参数", in1, "和参数", in2)
# 睡眠一定时间,单位是秒
time.sleep(3)
print("End loop 2 at: ", time.ctime())
def main():
print("Starting at: ", time.ctime())
# 生成threading.Thread()实例
t1 = threading.Thread(target=loop1, args=("Felix",))
t1.start()
t2 = threading.Thread(target=loop2, args=("Fang", "Bai"))
t2.start()
# time.sleep(6)知道上面的程序时间,手动添加等待时间
# 等待多线程执行完毕,在执行之后的代码,替代上面的功能
t1.join()
t2.join()
print("All done at: ", time.ctime())
if __name__ == '__main__':
main()
- 守护线程-setDaemon
- 如果在程序中子线程设置成守护线程
- 则子线程在主线程结束时也会自动退出
- 一般认为,守护线程不重要或者不允许离开主线程独立运行
- 守护线程案例能否有效运行跟环境有关
-
线程常用属性
-
threading.currentThread: 返回当前的线程变量
-
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
-
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
-
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
run(): 用以表示线程活动的方法。
start():启动线程活动。
join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。
-
-
直接继承threading.Thread
- 直接继承Thread
- 重写run函数
- 类实例可以直接运行
2. 共享变量
-
当多个线程同时访问一个变量的时候,会产生共享变量的问题
-
解决变量冲突问题
- 锁,信号灯
- 是一个标志,表示一个线程在占用一些资源
- 使用方法
- 上锁
- 使用共享资源,放心的使用
- 取消锁,释放锁
-
线程安全问题
- 如果一个资源或者变量,它对于多线程来讲,不用枷锁也不会引起任何问题,则为线程安全
- 线程不安全的变量类型:list, set, dict
- 线程安全变量类型: queue
-
生产消费者问题
- 一个模,可以用来搭建消息队列
- queue是一个用来存放变量的数据结构,特点是先进先出
- 内部元素需要排队,可以理解成一个特殊的list
-
死锁问题
3. 线程替代方案
- subprocess
- 完全跳过线程,使用进程
- 是派生进程的主要替代方案
- multiprocessing
- 使用threading接口派生
- 允许多核或者多cpu派生进程,接口跟threading相似
- concurrent.futures
- 新的异步执行模块
- 任务级别的操作
4. 多进程
-
类似QQ多开
-
完全独立的进程
-
主要问题:进程间通讯(InterprocessCommuication, IPC)
-
进程之前无任何共享状态
-
进程的创建
-
派生子类
-
在os中查看pid ppid以及他们的关系