线程
线程简介
- 在一个进程中,若想做多个子任务,我们把这些子任务称为线程。
- 线程可以理解为轻量级的进程。
- 进程之间的数据是独立的,而一个进程下的线程数据是共享的。
- 线程是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=' ')