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实例
  1. t = threading.Thread(target=xxx, args=(xxx,))
  2. t.start(): 启动多线程
  3. t.join(): 等待多线程执行完毕
  • 看案例28_6
    28-6
# 多线程实例
# 多线程传递参数
# 包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以及他们的关系