2014-06-18 31 views
5

我有一个长时间运行的Python脚本,它收集来自Twitter的推文,我想知道它每隔一段时间做一次。与长时间运行的python脚本进行交互

目前,我使用的是signal库捉中断,在这一点上,我打电话给我的打印功能。事情是这样的:

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> 

有没有更好的方式来做到这一点?我知道我可以在预定的时间间隔内使用我的脚本,但我更感兴趣的是了解需求并可能发布其他命令。

+0

这似乎是一个适用的使用信号库。你为什么认为有更好的办法? – MrAlias

+0

您可以让线程侦听连接的套接字,然后在客户端连接时将信息写入套接字。 – larsks

+0

@MrAlias我打算有多个“打印”方法,并且从我可以告诉的是我可以使用有限的中断,所以我想也许有一种不同的方式在运行时与我的程序进行交互。 – Tyler

回答

0

我个人信息写入到一个文件,以便我把它之后,虽然这有可能是稍微慢一点,因为它每一次,或者检索鸣叫每隔几次写入文件的缺点。

反正,如果你把它写入文件"output.txt",可以在tail output.txt打开bash和任一类型为文件中的打印的最新10行,也可以键入tail -f output.txt,它不断地与线更新终端提示您正在写入该文件。如果你想停止,只需Ctrl-C

0

下面是一个长期运行的程序示例,该程序还维护一个状态套接字。当客户端连接到套接字时,脚本将一些状态信息写入套接字。

#!/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 
0

我以前写一个类似的应用程序。

这里是我做过什么:

当有只需要几个命令,我只是用信号像你一样,只是为了不使它过于复杂。通过命令,我指的是您希望您的应用程序执行的操作,例如print_info

但是,当应用程序更新,有需要更多不同的命令,我开始用一个特殊的线程监听套接字端口或读本地文件接受命令。假设应用程序需要支持prinf_info1print_info2print_info3,所以你可以使用一个客户端连接到目标端口和写print_info1使应用程序执行命令print_info1(或者只写print_info1到本地文件,如果你正在使用读本地文件机制)。

使用的插座端口机制听,缺点是它需要更多的工作来写一个客户下达命令,其优点是你可以在任何地方发号施令。

当使用读取本地文件机制时,缺点是你必须让线程检查一个循环中的文件,它会使用一些资源,优点是命令很简单(只需写一个字符串一个文件),你不需要编写一个客户端和套接字监听服务器。

1

向进程发送信号会中断进程。下面你会发现一种使用专用线程来模拟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 

实施例的会话:

[email protected]:~$ 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() 
[email protected]:~$ 

这是一个可被用于一个相当强大的工具:

  • 转储线程,
  • 检查进程的内存,
  • 连接调试需求,pydev debugger(工作Eclipse和pycharm)
  • 力GC,在飞行

  • 猴补丁函数定义。

  • 0

    rpyc是完成此任务的理想工具。

    总之,您定义了一个rpyc.Service类,它公开您想要公开的命令,并启动一个rpyc.Server线程。

    然后,您的客户端连接到您的进程,并调用映射到您的服务公开的命令的方法。

    就像那样简单干净。无需担心套接字,信号,对象序列化。

    它还有其他很酷的功能,例如协议是对称的。

    0

    您的问题涉及进程间通信。您可以通过unix套接字或TCP端口进行通信,使用共享内存或使用消息队列或缓存系统(如RabbitMQ和Redis)来实现此目的。

    This post讨论使用mmap来实现共享内存进程间通信。

    以下是如何开始使用redisRabbitMQ,两者都相当容易实现。