1. 问题背景
该 Python 脚本旨在启动多个线程,每个线程又通过 Popen 启动一个子进程。子进程将从一个数据库中的表格中将 10M 条记录传输到另一个数据库中的不同表格中。这个过程中会涉及大量的数据整理和转换,因为两个数据库具有不同的架构。子进程在执行过程中,如果遇到错误(如错误的记录或重复的主键)或执行成功,都会输出 “Donen”;如果没有更多记录可供传输,则会输出 “NO DATAn”。
脚本 “tableTransfer.py” 意在生成这些子进程,读取它们的输出,并依此输出一些信息,如已完成的更新数量、剩余时间、已经过去的时间,以及每秒的传输数量。
然而,在运行这个脚本一段时间后,遇到了死锁问题。子进程没有在运行,还有记录需要更新,脚本也没有退出。它只是停在那里,不再输出当前信息,因为没有子进程运行来更新总完成数(这是控制输出更新的内容)。
2. 解决方案
2.1 使用队列通信
为了解决死锁问题,需要使用队列来进行进程间通信。队列是一个先进先出的数据结构,可以将数据从一个进程传输到另一个进程。在脚本中,可以创建一个队列来存储子进程的输出,然后由主进程从队列中读取输出并进行处理。这样,子进程就不会阻塞主进程,也不会发生死锁。
2.2 使用信号处理
为了处理 Ctrl C 中断信号,需要使用信号处理模块。该模块提供了处理不同信号的函数,包括 Ctrl C 中断信号。在脚本中,可以使用信号处理模块注册一个 Ctrl C 中断信号处理函数,当用户按下 Ctrl C 时,该函数将被调用。在处理函数中,可以关闭所有子进程并退出脚本。
2.3 优化脚本结构
为了提高脚本的可读性和可维护性,可以对脚本的结构进行优化。例如,可以将脚本划分为不同的函数,每个函数负责一个特定的任务。还可以使用面向对象编程来组织代码,使代码更加模块化和易于复用。
2.4 代码示例
代码语言:python代码运行次数:0复制import queue
import threading
import signal
import subprocess
# 创建一个队列来存储子进程的输出
output_queue = queue.Queue()
# 创建一个函数来处理子进程的输出
def process_output(output):
# 在这里处理子进程的输出
# ...
# 创建一个函数来启动一个子进程
def start_subprocess(command):
# 启动一个子进程
process = subprocess.Popen(command, stdout=subprocess.PIPE)
# 将子进程的输出添加到队列中
for line in iter(process.stdout.readline, b''):
output_queue.put(line.decode('utf-8'))
# 等待子进程完成
process.wait()
# 创建一个函数来处理 Ctrl C 中断信号
def signal_handler(signal, frame):
# 关闭所有子进程
for thread in threads:
thread.join()
# 退出脚本
exit()
# 注册 Ctrl C 中断信号处理函数
signal.signal(signal.SIGINT, signal_handler)
# 创建一个列表来存储线程
threads = []
# 启动一定数量的线程来启动子进程
for i in range(10):
thread = threading.Thread(target=start_subprocess, args=('python script.py',))
threads.append(thread)
thread.start()
# 从队列中读取输出并进行处理
while True:
output = output_queue.get()
process_output(output)