python3中断多线程的合适方法
我正在编写一个多线程网络爬虫,每个线程的例程函数基本上是一个无止境的循环,有一个共享字典来存储那些已经访问过的url,我使用线程锁来同步 有时我可能想用ctrl+c来中断它,我在线程运行函数中添加了一个try-catch来捕获键盘中断,然后我可能想做一些最终的任务,例如将数据转储到数据库或pkl文件 问题是,每次我打断它,它就无法进入捕获过程,有时它只是停留在那里,有时它仍然在运行 那么,在多线程编程中处理异常/中断的最佳实践是什么呢 我的代码如下:python3中断多线程的合适方法,python,multithreading,python-3.x,Python,Multithreading,Python 3.x,我正在编写一个多线程网络爬虫,每个线程的例程函数基本上是一个无止境的循环,有一个共享字典来存储那些已经访问过的url,我使用线程锁来同步 有时我可能想用ctrl+c来中断它,我在线程运行函数中添加了一个try-catch来捕获键盘中断,然后我可能想做一些最终的任务,例如将数据转储到数据库或pkl文件 问题是,每次我打断它,它就无法进入捕获过程,有时它只是停留在那里,有时它仍然在运行 那么,在多线程编程中处理异常/中断的最佳实践是什么呢 我的代码如下: from bs4 import Beauti
from bs4 import BeautifulSoup
import requests
import threading
import queue
import pickle
import os
from concurrent.futures import ThreadPoolExecutor
worker_num = 8
q = queue.Queue()
lock = threading.Lock()
if os.path.exists('./checked.pkl'):
with open('./checked.pkl', 'rb') as f:
checked = pickle.load(f)
else:
checked = set()
def get_links(url):
# do sth....
def run():
print(threading.current_thread())
try:
while True:
next_url = q.get()
links = get_links(next_url)
lock.acquire()
for link in links:
if link not in checked:
q.put(link)
print(len(checked))
lock.release()
except Exception as e:
print(e)
print('interrupt')
lock.acquire()
with open('./checked.pkl', 'wb') as f:
pickle.dump(checked, f)
lock.release()
if __name__ == '__main__':
q.put(start_url)
with ThreadPoolExecutor(worker_num) as executor:
for _ in range(worker_num):
executor.submit(run)
键盘中断始终在主线程中引发。您无法在其他线程中处理它
您应该在每个成功的工作块之后检查您的状态(不必在每个URL之后,但也可以在每个URL之后)。这将为您提供状态更新,即使您的进程因其他原因崩溃(某些不可处理的原因,如segfault或整个主机崩溃)。您还应该以原子方式编写检查点,这样,如果在更新过程中崩溃,就不会导致损坏、无法使用的状态。(由于pickle的不安全性、脆弱性和跨语言挑战,也不应将其用作检查点状态格式。)
一旦在正常操作期间安全且定期地写入状态更新,就可以通过将工作线程设置为守护进程线程并向主线程添加KeyboardInterrupt
处理来使爬虫程序可中断。在这一点上,如果工作线程在没有清理机会的情况下被杀死(如果您让它们成为守护线程并让主线程退出,就会发生这种情况),这无关紧要,因为它们最近已经检查了它们的状态
此外,您应该考虑使用现有的爬行工具,而不是滚动自己。
<代码>键盘中断> /COD>总是在主线程中引发。您无法在其他线程中处理它
您应该在每个成功的工作块之后检查您的状态(不必在每个URL之后,但也可以在每个URL之后)。这将为您提供状态更新,即使您的进程因其他原因崩溃(某些不可处理的原因,如segfault或整个主机崩溃)。您还应该以原子方式编写检查点,这样,如果在更新过程中崩溃,就不会导致损坏、无法使用的状态。(由于pickle的不安全性、脆弱性和跨语言挑战,也不应将其用作检查点状态格式。)
一旦在正常操作期间安全且定期地写入状态更新,就可以通过将工作线程设置为守护进程线程并向主线程添加KeyboardInterrupt
处理来使爬虫程序可中断。在这一点上,如果工作线程在没有清理机会的情况下被杀死(如果您让它们成为守护线程并让主线程退出,就会发生这种情况),这无关紧要,因为它们最近已经检查了它们的状态
此外,您应该考虑使用现有的爬行工具,而不是滚动自己。