与长时间运行的python脚本交互
我有一个长期运行的Python脚本,它可以收集Twitter上的tweet,我想知道它每隔一段时间是如何运行的 目前,我正在使用与长时间运行的python脚本交互,python,Python,我有一个长期运行的Python脚本,它可以收集Twitter上的tweet,我想知道它每隔一段时间是如何运行的 目前,我正在使用信号库捕获中断,此时我调用打印函数。大概是这样的: import signal def print_info(count): print "#Tweets:", count #Print out the process ID so I can interrupt it for info print 'PID:', os.getpid() #Start li
信号
库捕获中断,此时我调用打印函数。大概是这样的:
import signal
def print_info(count):
print "#Tweets:", count
#Print out the process ID so I can interrupt it for info
print 'PID:', os.getpid()
#Start listening for interrupts
signal.signal(signal.SIGUSR1, functools.partial(print_info, tweet_count))
每当我需要我的信息时,我就会打开一个新的终端并发出我的中断:
$kill -USR1 <pid>
$kill-USR1
有更好的方法吗?我知道我可以按预定的时间间隔编写脚本,但我更感兴趣的是了解随需应变,并可能发出其他命令。我个人将信息写入文件,以便在以后获得它,尽管这样做的缺点可能是速度稍慢,因为它每次或每隔几次检索tweet时都必须写入文件
无论如何,如果您将其写入一个文件
“output.txt”
,您可以打开bash
,输入tail output.txt
,查看文件中打印的最新10行,或者输入tail-f output.txt
,它会用您正在写入文件的行不断更新终端提示。如果您想停止,只需按住Ctrl-C键即可 下面是一个长时间运行的程序示例,它还维护一个状态套接字。当客户端连接到套接字时,脚本将一些状态信息写入套接字
#!/usr/bin/python
import os
import sys
import argparse
import random
import threading
import socket
import time
import select
val1 = 0
val2 = 0
lastupdate = 0
quit = False
# This function runs in a separate thread. When a client connects,
# we write out some basic status information, close the client socket,
# and wait for the next connection.
def connection_handler(sock):
global val1, val2, lastupdate, quit
while not quit:
# We use select() with a timeout here so that we are able to catch the
# quit flag in a timely manner.
rlist, wlist, xlist = select.select([sock],[],[], 0.5)
if not rlist:
continue
client, clientaddr = sock.accept()
client.send('%s %s %s\n' % (lastupdate, val1, val2))
client.close()
# This function starts the listener thread.
def start_listener():
sock = socket.socket(socket.AF_UNIX)
try:
os.unlink('/var/tmp/myprog.socket')
except OSError:
pass
sock.bind('/var/tmp/myprog.socket')
sock.listen(5)
t = threading.Thread(
target=connection_handler,
args=(sock,))
t.start()
def main():
global val1, val2, lastupdate
start_listener()
# Here is the part of our script that actually does "work".
while True:
print 'updating...'
lastupdate = time.time()
val1 = val1 + random.randint(1,10)
val2 = val2 + random.randint(100,200)
print 'sleeping...'
time.sleep(5)
if __name__ == '__main__':
try:
main()
except (Exception,KeyboardInterrupt,SystemExit):
quit=True
raise
您可以编写一个简单的Python客户端来连接到套接字,也可以使用类似于socat
:
$ socat - unix:/var/tmp/myprog.sock
1403061693.06 6 152
我以前也写过类似的申请 以下是我所做的: 当只需要几个命令时,我只是像你们一样使用信号,只是为了不让它太复杂。我所说的命令,是指您希望应用程序执行的操作,例如在您的帖子中打印信息 但当应用程序更新时,需要更多不同的命令,我开始使用一个特殊的线程监听套接字端口或读取本地文件来接受命令。假设应用程序需要支持
prinf_info1
print_info2
print_info3
,因此您可以使用客户端连接到目标端口并写入print_info1,以使应用程序执行命令print_info1(或者如果使用读取本地文件机制,只需将print_info1写入本地文件)
当使用套接字端口监听机制时,缺点是编写客户端来发出命令需要更多的工作,优点是您可以在任何地方发出命令
使用“读取本地文件”机制时,缺点是必须让线程在循环中检查文件,这将使用位资源,优点是命令非常简单(只需将字符串写入文件)您不需要编写客户端和套接字侦听服务器。向进程发送信号会中断进程。下面您将找到一种使用专用线程来模拟python控制台的方法。控制台作为unix套接字公开
import traceback
import importlib
from code import InteractiveConsole
import sys
import socket
import os
import threading
from logging import getLogger
# template used to generate file name
SOCK_FILE_TEMPLATE = '%(dir)s/%(prefix)s-%(pid)d.socket'
log = getLogger(__name__)
class SocketConsole(object):
'''
Ported form :eventlet.backdoor.SocketConsole:.
'''
def __init__(self, locals, conn, banner=None): # pylint: diable=W0622
self.locals = locals
self.desc = _fileobject(conn)
self.banner = banner
self.saved = None
def switch(self):
self.saved = sys.stdin, sys.stderr, sys.stdout
sys.stdin = sys.stdout = sys.stderr = self.desc
def switch_out(self):
sys.stdin, sys.stderr, sys.stdout = self.saved
def finalize(self):
self.desc = None
def _run(self):
try:
console = InteractiveConsole(self.locals)
# __builtins__ may either be the __builtin__ module or
# __builtin__.__dict__ in the latter case typing
# locals() at the backdoor prompt spews out lots of
# useless stuff
import __builtin__
console.locals["__builtins__"] = __builtin__
console.interact(banner=self.banner)
except SystemExit: # raised by quit()
sys.exc_clear()
finally:
self.switch_out()
self.finalize()
class _fileobject(socket._fileobject):
def write(self, data):
self._sock.sendall(data)
def isatty(self):
return True
def flush(self):
pass
def readline(self, *a):
return socket._fileobject.readline(self, *a).replace("\r\n", "\n")
def make_threaded_backdoor(prefix=None):
'''
:return: started daemon thread running :main_loop:
'''
socket_file_name = _get_filename(prefix)
db_thread = threading.Thread(target=main_loop, args=(socket_file_name,))
db_thread.setDaemon(True)
db_thread.start()
return db_thread
def _get_filename(prefix):
return SOCK_FILE_TEMPLATE % {
'dir': '/var/run',
'prefix': prefix,
'pid': os.getpid(),
}
def main_loop(socket_filename):
try:
log.debug('Binding backdoor socket to %s', socket_filename)
check_socket(socket_filename)
sockobj = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sockobj.bind(socket_filename)
sockobj.listen(5)
except Exception, e:
log.exception('Failed to init backdoor socket %s', e)
return
while True:
conn = None
try:
conn, _ = sockobj.accept()
console = SocketConsole(locals=None, conn=conn, banner=None)
console.switch()
console._run()
except IOError:
log.debug('IOError closing connection')
finally:
if conn:
conn.close()
def check_socket(socket_filename):
try:
os.unlink(socket_filename)
except OSError:
if os.path.exists(socket_filename):
raise
示例程序:
make_threaded_backdoor(prefix='test')
while True:
pass
示例会话:
mmatczuk@cactus:~$ rlwrap nc -U /var/run/test-3196.socket
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import os
>>> os.getpid()
3196
>>> quit()
mmatczuk@cactus:~$
这是一个非常强大的工具,可用于:
- 转储线程
- 检查进程内存
- 按需附加调试器(适用于eclipse和pycharm)
- 警队总指挥官
- monkeypatch函数动态定义
rpyc.Server
线程
然后,客户端连接到进程,并调用映射到服务公开的命令的方法
就这么简单干净。无需担心套接字、信号和对象序列化
它还有其他很酷的特性,例如协议是对称的。您的问题与进程间通信有关。您可以通过unix套接字或TCP端口通信、使用共享内存或使用消息队列或缓存系统(如RabbitMQ和Redis)来实现这一点 讨论使用mmap实现共享内存进程间通信
这是如何开始使用和的,两者都很容易实现。这似乎是一个适用的使用信号库。为什么你认为有更好的方法?你可以让线程监听套接字上的连接,然后在客户端连接时将信息写入套接字。@MrAlias我计划使用不止一种“打印”方法,根据我所知,我可以使用有限的中断,所以我想也许在运行时有一种不同的方式与我的程序交互。如果只有一个或几个命令,我想信号就足够了。但是如果您有很多不同的命令,我更喜欢使用线程侦听套接字或仅读取文件来接受命令。知道
signal可能会有所帮助。signal
发送信号号和帧,并且您可以从帧中提取信息,如全局和局部变量(可能是tweet_counts和其他所需的状态对象…)。否则,如果您喜欢将信息保存到文件中,则该模块将是一个不错的选择。很好。对我来说非常有用的片段。投票通过,但需要在python 3中使用。这里是python 3版本,应该可以使用。我认为:AttributeError:module'socket'没有属性'\u fileobject'