线程
线程简介
- 在一个进程中,若想做多个子任务,我们把这些子任务称为线程。
- 线程可以理解为轻量级的进程。
- 进程之间的数据是独立的,而一个进程下的线程数据是共享的。
- 线程是CPU分配的最小单位。 进程和线程的调度都是操作系统的事。
- 一个进程默认有一个线程,我们称为主线程。
线程模块
- **_thread:**低级模块
- **threading:**高级模块,是对 _thread的封装
- 以后建议大家使用高级模块 threading
线程模块 _thread
- 
示例: 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16import _thread 
 import time
 def loop():
 print('子线程开始')
 print('子线程结束')
 if __name__ == '__main__':
 print('主线程开始')
 # 创建线程
 _thread.start_new_thread(loop, ())
 # 主线程结束,子线程立即结束,通过延时测试
 time.sleep(3)
 print('主线程结束')非常简陋,不建议使用 
线程模块 threading
- 
基本使用 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37import time 
 import threading
 def run(num):
 c = threading.current_thread()
 time.sleep(3)
 print('子线程开始', c.name)
 print(num)
 print('子线程结束', c.name)
 if __name__ == '__main__':
 # 获取主线程
 t = threading.main_thread()
 print('主线程开始:', t.name)
 # 获取当前线程
 # c = threading.current_thread()
 # print('当前线程:', c.name)
 # 创建子线程
 sub = threading.Thread(target=run, args=(250,), name='下载美女图片')
 # 启动子线程
 sub.start()
 # 活跃线程个数
 # print(threading.active_count())
 # 线程列表
 # print(threading.enumerate())
 time.sleep(1)
 # 判断线程是否是活着的
 print(sub.is_alive())
 # 等待子线程
 sub.join()
 print(sub.is_alive())
 print('主线程结束:', t.name)
数据共享
- 
**示例1:**全局变量可以共享 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28import threading 
 # 全局变量
 num = 250
 def thread_one():
 global num
 num += 10
 def thread_two():
 global num
 num -= 100
 if __name__ == '__main__':
 print('主线程:', num)
 t1 = threading.Thread(target=thread_one)
 t1.start()
 t1.join()
 print('主线程:', num)
 t2 = threading.Thread(target=thread_two)
 t2.start()
 t2.join()
 print('主线程:', num)线程之间共享进程的所有数据 
- 
**示例2:**多线程操作同一变量,可能会出错。 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27import threading 
 # 这是你银行的存款
 money = 250
 def run(n):
 global money
 for i in range(100000):
 # 运算之后数据应该不变
 money += n
 money -= n
 if __name__ == '__main__':
 while True:
 t1 = threading.Thread(target=run, args=(10,))
 t2 = threading.Thread(target=run, args=(15,))
 t1.start()
 t2.start()
 t1.join()
 t2.join()
 if money != 250:
 break
 print(money)
- 
**示例3:**加锁解决数据错乱问题(线程锁) 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38import threading 
 # 这是你银行的存款
 money = 250
 def run(n):
 global money
 for i in range(100000):
 '''
 lock.acquire()
 try:
 # 运算之后数据应该不变
 money += n
 money -= n
 finally:
 lock.release()
 '''
 # 简化书写
 with lock:
 money = money + n
 money = money - n
 if __name__ == '__main__':
 lock = threading.Lock()
 while True:
 t1 = threading.Thread(target=run, args=(10,))
 t2 = threading.Thread(target=run, args=(15,))
 t1.start()
 t2.start()
 t1.join()
 t2.join()
 if money != 250:
 break
 print(money)
自定义线程类
- **说明:**需要继承自 Thread 类,还需要重写 run 方法,开启线程时自动调用 run 方法
- 示例:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21import time 
 from threading import Thread
 class MyTtread(Thread):
 def __init__(self, t):
 super().__init__()
 self.t = t
 def run(self):
 for i in range(3):
 print('子线程中...')
 time.sleep(self.t)
 if __name__ == '__main__':
 print('主线程开始')
 p = MyTtread(2)
 p.start()
 p.join()
 print('主线程结束')
定时线程
- **说明:**在 threading 模块中,有一个 Timer 类,继承自 Thread 类,可以延迟执行线程任务。
- 示例:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13import os 
 import threading
 def run():
 os.system('start notepad++')
 if __name__ == '__main__':
 # 延迟指定时间才会执行的任务
 t = threading.Timer(3, run)
 t.start()
 t.join()
信号传递(Event)
- **说明:**通常用于控制线程的执行
- 示例:1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22import time 
 import threading
 def run(num):
 for i in range(num):
 # 等待条件成立,会阻塞
 e.wait()
 print('第%d步' % (i + 1))
 # 清除条件
 e.clear()
 if __name__ == '__main__':
 e = threading.Event()
 threading.Thread(target=run, args=(3,)).start()
 for i in range(3):
 time.sleep(1)
 # 设置后,wait处将不再阻塞
 e.set()
 print('走你,', end=' ')