python threading库中,start()、join()方法的用法是什么?daemo参数的含义是什么?

我来详细解释 Python threading 库中的这些重要概念。

start() 方法

start() 方法用于启动线程,使其开始执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import threading
import time

def worker():
print("线程开始执行")
time.sleep(2)
print("线程执行完毕")

# 创建线程
t = threading.Thread(target=worker)

# 启动线程
t.start() # 线程开始执行

print("主线程继续执行")

特点:

  • 每个线程只能调用一次 start()
  • 调用后线程进入就绪状态,等待 CPU 调度
  • 立即返回,不会阻塞主线程

join() 方法

join() 方法用于等待线程执行完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import threading
import time

def worker(name):
print(f"{name} 开始工作")
time.sleep(2)
print(f"{name} 工作完成")

# 创建线程
t1 = threading.Thread(target=worker, args=("线程1",))
t2 = threading.Thread(target=worker, args=("线程2",))

# 启动线程
t1.start()
t2.start()

print("主线程等待子线程完成...")

# 等待线程完成
t1.join() # 主线程阻塞,直到 t1 完成
t2.join() # 主线程阻塞,直到 t2 完成

print("所有线程执行完毕")

带超时的 join:

1
2
3
4
5
6
# 最多等待 1 秒
t1.join(timeout=1.0)
if t1.is_alive():
print("线程仍在运行,超时了")
else:
print("线程已完成")

daemon 参数

daemon(守护线程)参数决定线程是否随主线程结束而强制结束。

非守护线程 (daemon=False,默认值)

1
2
3
4
5
6
7
8
9
10
11
12
import threading
import time

def worker():
print("非守护线程开始")
time.sleep(3)
print("非守护线程结束") # 这会正常执行

t = threading.Thread(target=worker, daemon=False)
t.start()

print("主线程结束") # 程序会等待非守护线程完成

守护线程 (daemon=True)

1
2
3
4
5
6
7
8
9
10
11
12
import threading
import time

def worker():
print("守护线程开始")
time.sleep(3)
print("守护线程结束") # 这可能不会执行,因为主线程已结束

t = threading.Thread(target=worker, daemon=True)
t.start()

print("主线程结束") # 程序立即结束,不等待守护线程

完整示例

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
import threading
import time

def worker(name, delay, is_daemon):
print(f"{name} 开始执行 (daemon={is_daemon})")
time.sleep(delay)
print(f"{name} 执行完成 (daemon={is_daemon})")

# 创建守护线程和非守护线程
daemon_thread = threading.Thread(
target=worker,
args=("守护线程", 3, True),
daemon=True
)

normal_thread = threading.Thread(
target=worker,
args=("非守护线程", 2, False),
daemon=False
)

# 启动线程
daemon_thread.start()
normal_thread.start()

print("主线程继续执行...")
time.sleep(1)
print("主线程等待非守护线程...")

# 只等待非守护线程
normal_thread.join()

print("主线程结束")
# 守护线程会被强制终止

关键点总结

方法/参数 作用 说明
start() 启动线程 线程开始执行,立即返回
join() 等待线程完成 阻塞调用线程直到目标线程完成
daemon=True 设置为守护线程 主线程结束时强制终止该线程
daemon=False 设置为非守护线程 主线程会等待该线程完成

使用建议:

  • 对于需要在后台运行但不重要的任务,使用守护线程
  • 对于需要确保完成的重要任务,使用非守护线程
  • 使用 join() 来控制线程执行顺序和同步

Event的set()和is_set()方法的原理和用法?

我来详细讲解 threading.Event 的 set()is_set() 方法的原理和用法。

Event 的基本概念

Event 是一个简单的线程同步工具,它内部维护一个标志位,线程可以等待这个标志位被设置。

核心方法

set() 方法

  • 作用:将 Event 的内部标志设置为 True
  • 效果:唤醒所有等待该 Event 的线程
  • 特点:一旦设置为 True,会一直保持,直到手动清除

is_set() 方法

  • 作用:检查 Event 的内部标志是否为 True
  • 返回值TrueFalse
  • 特点:非阻塞,立即返回当前状态

其他重要方法

  • clear():将标志重置为 False
  • wait(timeout=None):阻塞直到标志为 True 或超时

用法示例

基本用法

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
import threading
import time

# 创建 Event 对象
event = threading.Event()

def worker(name):
print(f"{name} 等待事件触发...")
event.wait() # 阻塞直到 event.set() 被调用
print(f"{name} 检测到事件,继续执行")

# 创建多个线程
threads = []
for i in range(3):
t = threading.Thread(target=worker, args=(f"线程-{i}",))
t.start()
threads.append(t)

print("主线程:3秒后触发事件")
time.sleep(3)

print("主线程:设置事件")
event.set() # 唤醒所有等待的线程

# 等待所有线程完成
for t in threads:
t.join()

print("所有线程执行完毕")

使用 is_set() 检查状态

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
import threading
import time

event = threading.Event()

def status_checker():
while True:
if event.is_set():
print("事件已触发,执行任务...")
time.sleep(1)
else:
print("事件未触发,等待中...")
time.sleep(0.5)

# 检查是否需要退出
if event.is_set() and some_condition:
break

def trigger():
time.sleep(2)
print("触发器:设置事件")
event.set()

# 启动线程
threading.Thread(target=status_checker).start()
threading.Thread(target=trigger).start()

一次性事件模式

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
38
39
40
import threading
import time

class TaskCoordinator:
def __init__(self):
self.start_event = threading.Event()
self.complete_event = threading.Event()

def worker(self, name):
print(f"{name} 等待开始信号...")
self.start_event.wait() # 等待开始命令

print(f"{name} 开始工作...")
time.sleep(2) # 模拟工作
print(f"{name} 工作完成")

# 通知任务完成
self.complete_event.set()

def start_workers(self, num_workers):
workers = []
for i in range(num_workers):
t = threading.Thread(target=self.worker, args=(f"Worker-{i}",))
t.start()
workers.append(t)

# 等待所有worker就绪
time.sleep(1)

# 发出开始信号
print("协调器:开始所有工作线程")
self.start_event.set()

# 等待所有worker完成
self.complete_event.wait()
print("协调器:所有工作线程已完成")

# 使用示例
coordinator = TaskCoordinator()
coordinator.start_workers(3)

超时等待示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import threading
import time

event = threading.Event()

def waiter(name, timeout):
print(f"{name} 开始等待,超时时间: {timeout}秒")
if event.wait(timeout=timeout):
print(f"{name} 成功等到事件")
else:
print(f"{name} 等待超时")

def setter():
time.sleep(2)
print("Setter: 设置事件")
event.set()

# 创建多个等待线程,超时时间不同
threading.Thread(target=waiter, args=("快速等待", 1)).start()
threading.Thread(target=waiter, args=("正常等待", 3)).start()
threading.Thread(target=setter).start()

重复使用 Event

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
import threading
import time

class ReusableEvent:
def __init__(self):
self.event = threading.Event()

def worker(self, name):
for i in range(3):
print(f"{name}{i+1}次等待...")
self.event.wait() # 等待事件触发
print(f"{name}{i+1}次被唤醒")
self.event.clear() # 重置事件,准备下一次等待

def controller(self):
for i in range(3):
time.sleep(2)
print(f"控制器:第{i+1}次触发")
self.event.set() # 触发所有等待的线程
time.sleep(0.1) # 给线程一些时间响应

# 使用示例
reusable = ReusableEvent()

# 启动工作线程
for i in range(2):
threading.Thread(target=reusable.worker, args=(f"Worker-{i}",)).start()

# 启动控制器线程
controller_thread = threading.Thread(target=reusable.controller)
controller_thread.start()
controller_thread.join()

原理说明

  1. 内部标志:Event 内部维护一个布尔值标志
  2. set():将标志设为 True,并通知所有等待的线程
  3. is_set():立即返回当前标志状态,不阻塞
  4. wait():如果标志为 False则阻塞,为 True则立即返回
  5. clear():将标志重置为 False

使用场景

  • 线程协调:一个线程通知多个线程开始执行
  • 资源就绪通知:当某个资源准备好时通知等待线程
  • 任务调度:控制多个线程的执行时机
  • 系统状态管理:表示系统是否处于某种特定状态

Event 提供了一种简单而强大的线程间通信机制,特别适合”一触即发”的场景。