一. 前言

在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...')

运行结果: 可以看出程序依次执行完所有的代码。

Python - 多线程,多进程中的join和Event及没有使用join和event区别_服务器

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只是部分的等待。

Python - 多线程,多进程中的join和Event及没有使用join和event区别_子进程_02

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循环代码执行完。

Python - 多线程,多进程中的join和Event及没有使用join和event区别_子进程_03

附上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()方法时,需要考虑线程或进程之间的同步和互斥问题,避免死锁和竞争条件。