一. 前言
在Python的多线程和多进程编程中,join()
和 Event
都是用来控制线程或进程之间的同步关系的工具,它们的作用类似,但还是有一些区别。
二. 概念
1. join()
join()
方法是线程或进程实例的一个方法,用于阻塞当前调用线程或进程,直到该线程或进程执行完成后才能继续执行后续代码。join()
方法常用于等待另一个线程或进程的完成。在父进程中,可以使用 join()
来等待所有子进程完成之后再继续执行父进程的代码。
2. Event
Event
是一个线程或进程同步机制,主要用于线程之间的通信。一个 Event
表示一个内部标志,可以设置或清除。可以使用 set()
方法设置 Event 标志,并使用 wait()
方法等待标志被设置。另外,还可以使用 clear()
方法清除标志。
三. 区别
-
join()
属于线程或进程的实例方法,只能在当前线程或进程中使用,Event
则可以跨线程或进程共享。 -
join()
的作用是等待线程或进程执行完成,以便继续执行后续代码;Event
的作用是线程之间的同步和通信,实现局部的等待。
总的来说,join() 适用于控制线程或进程之间的执行顺序,而 Event 则适用于实现线程之间的同步和通信,只是局部的等待。
四. 示例代码
下面以线程为例,进程的实现也是类似。
1. 使用join()
等待某一个线程全部执行完才执行下一步
# -*- coding:utf-8 -*-
import time
import threading
def run(n, event):
for i in range(1000):
print(i, end=' ')
# event.set()
while n > 0:
print('Threading:', n)
n -= 1
time.sleep(1)
event = threading.Event()
if __name__ == '__main__':
print('start threading.')
t = threading.Thread(target=run, args=(5, event))
t.start()
t.join()
# event.wait()
print('end threading...')
运行结果: 可以看出程序依次执行完所有的代码。
2. 使用Event
等待线程中一部分代码执行才执行后面的代码
# -*- coding:utf-8 -*-
import time
import threading
def run(n, event):
for i in range(1000):
print(i, end=' ')
event.set()
while n > 0:
print('Threading:', n)
n -= 1
time.sleep(1)
event = threading.Event()
if __name__ == '__main__':
print('start threading.')
t = threading.Thread(target=run, args=(5, event))
t.start()
# t.join()
event.wait()
print('end threading.')
运行效果:可以看出,end threading
只是等待了for 循环这个代码之前代码运行完就运行了。说明Event只是部分的等待。
3. 不使用event和join
代码
# -*- coding:utf-8 -*-
import time
import threading
def run(n, event):
for i in range(1000):
print(i, end=' ')
# event.set()
while n > 0:
print('Threading:', n)
n -= 1
time.sleep(1)
event = threading.Event()
if __name__ == '__main__':
print('start threading.')
t = threading.Thread(target=run, args=(5, event))
t.start()
print('end threading.')
运行效果:可以看出end threading
先于for 循环运行了,并没有等待for循环代码执行完。
附上windwos中查看进程线程数量的几种方法
方法一
# 获取 WMI 对象
wmi = win32com.client.GetObject("winmgmts:")
# 查询进程信息
process_query = "SELECT * FROM Win32_Process"
process_result = wmi.ExecQuery(process_query)
process_count = len(process_result)
# 查询线程信息
thread_query = "SELECT * FROM Win32_Thread"
thread_result = wmi.ExecQuery(thread_query)
thread_count = len(thread_result)
print("系统进程数量:", process_count)
print("系统线程数量:", thread_count)
方法二
import psutil
# 获取进程数量
process_count = len(psutil.pids())
print("进程数量:", process_count)
# 获取线程数量
thread_count = 0
for proc in psutil.process_iter(['pid', 'name']):
try:
pinfo = proc.as_dict(attrs=['pid', 'name', 'num_threads'])
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
else:
thread_count += pinfo['num_threads']
print("线程数量:", thread_count)
方法三
import multiprocessing
import threading
print(f"Process {multiprocessing.current_process().pid}: {threading.active_count()} threads")
print(f"Process {threading.current_thread()}: {threading.active_count()} threads")
print(f"Total threads: {threading.active_count()}")
print(f"Total processes: {len(multiprocessing.active_children())}")
五. 总结
- 在主线程或主进程执行时,需要等待子线程或子进程完成某个任务,才能继续执行后续操作。如果没有使用join()方法,主线程或主进程可能会在子线程或子进程未完成任务时就已经退出,导致程序异常或结果不正确。
- join()和Event都是多线程和多进程编程中非常重要的同步工具,它们可以使程序更加可靠和高效。当程序需要等待其他线程或进程完成后才能继续执行时,可以使用join()方法;当程序需要协调和通信多个线程或进程时,可以使用Event。
当然,与此同时,要注意使用join()方法时,需要考虑线程或进程之间的同步和互斥问题,避免死锁和竞争条件。