我想知道如何使用CTRL + C或类似的smth在控制台中停止我的程序。 问题是我的程序中有两个线程。线程1抓取Web并提取一些数据,线程2以可读格式显示该数据供用户使用。两个部分共享相同的数据库我像这样运行它们:
from threading import Thread
import ResultsPresenter
def runSpider():
Thread(target=initSpider).start()
Thread(target=ResultsPresenter.runPresenter).start()
if __name__ == "__main__":
runSpider()
我该怎么做?
好的,所以我创建了自己的线程类:
import threading
class MyThread(threading.Thread):
"""Thread class with a stop() method. The thread itself has to check
regularly for the stopped() condition."""
def __init__(self):
super(MyThread, self).__init__()
self._stop = threading.Event()
def stop(self):
self._stop.set()
def stopped(self):
return self._stop.isSet()
好的,所以我会在这里发布resultPresenter和crawler的片段。 这是resultPresenter的代码:
# configuration
DEBUG = False
DATABASE = database.__path__[0] + '/database.db'
app = Flask(__name__)
app.config.from_object(__name__)
app.config.from_envvar('CRAWLER_SETTINGS', silent=True)
def runPresenter():
url = "http://127.0.0.1:5000"
webbrowser.open_new(url)
app.run()
此处还有两个省略的方法 - 其中一个连接到数据库,第二个方法加载html模板以显示结果。我重复这个,直到满足条件或用户停止程序(我正在尝试实现)。还有另外两种方法 - 一个从命令行获取初始链接和第二个valitated参数 - 如果参数无效,我将不运行crawl()方法。
以下是抓取工具的简短版本:
def crawl(initialLink, maxDepth):
#here I am setting initial values, lists etc
while not(depth >= maxDepth or len(pagesToCrawl) <= 0):
#this is the main loop that stops when certain depth is
#reached or there is nothing to crawl
#Here I am popping urls from url queue, parse them and
#insert interesting data into the database
parser.close()
sock.close()
dataManager.closeConnection()
这是 init 文件,它在线程中启动这些模块:
import ResultsPresenter, MyThread, time, threading
def runSpider():
MyThread.MyThread(target=initSpider).start()
MyThread.MyThread(target=ResultsPresenter.runPresenter).start()
def initSpider():
import Crawler
import database.__init__
import schemas.__init__
import static.__init__
import templates.__init__
link, maxDepth = Crawler.getInitialLink()
if link:
Crawler.crawl(link, maxDepth)
killall = False
if __name__ == "__main__":
global killall
runSpider()
while True:
try:
time.sleep(1)
except:
for thread in threading.enumerate():
thread.stop()
killall = True
raise
答案 0 :(得分:3)
杀死线程不是一个好主意,因为(正如你已经说过的)他们可能正在对数据库执行一些关键操作。因此,您可以定义全局标志,它将通知线程他们应该完成他们正在做的事情并退出。
killall = False
import time
if __name__ == "__main__":
global killall
runSpider()
while True:
try:
time.sleep(1)
except:
/* send a signal to threads, for example: */
killall = True
raise
并在每个线程中检查一个类似的循环,killall
变量是否设置为True
。如果它关闭所有活动并退出线程。
修改强>
首先:异常是相当明显的。您将target
参数传递给__init__
,但未在__init__
中声明。这样做:
class MyThread(threading.Thread):
def __init__(self, *args, **kwargs):
super(MyThread, self).__init__(*args, **kwargs)
self._stop = threading.Event()
其次:你没有使用我的代码。正如我所说:设置标志并在线程中检查它。当我说“线程”时,我实际上是指处理程序,即ResultsPresenter.runPresenter
或initSpide
。向我们展示其中一个的代码,我将向您展示如何处理停止。
编辑2
假设crawl
函数的代码在同一个文件中(如果不是,那么你必须导入killall
变量),你可以做这样的事情
def crawl(initialLink, maxDepth):
global killall
# Initialization.
while not killall and not(depth >= maxDepth or len(pagesToCrawl) <= 0):
# note the killall variable in while loop!
# the other code
parser.close()
sock.close()
dataManager.closeConnection()
所以基本上你只是说:“嘿,线程,现在退出循环!”。或者你可以打破一个循环:
while not(depth >= maxDepth or len(pagesToCrawl) <= 0):
# some code
if killall:
break
当然它还需要一段时间才能退出(必须完成循环并关闭解析器,套接字等),但它应该安全地退出。这至少就是这个想法。
答案 1 :(得分:1)
试试这个:
ps aux | grep python
复制要杀死的进程的ID,并且:
kill -3 <process_id>
在您的代码中(改编自here):
import signal
import sys
def signal_handler(signal, frame):
print 'You killed me!'
sys.exit(0)
signal.signal(signal.SIGQUIT, signal_handler)
print 'Kill me now'
signal.pause()