Python wait until data is in sys.stdin

后端 未结 9 1243
隐瞒了意图╮
隐瞒了意图╮ 2020-12-15 23:00

my problem is the following:

My pythons script receives data via sys.stdin, but it needs to wait until new data is available on sys.stdin.

As described in th

相关标签:
9条回答
  • 2020-12-15 23:07

    Use this:

    #!/usr/bin/python
    import sys
    for line in sys.stdin.readlines():
        pass # do something useful
    
    0 讨论(0)
  • 2020-12-15 23:07

    I've come back to problem after a long time. The issue appears to be that Apache treats a CustomLog like a file -- something it can open, write to, close, and then reopen at a later date. This causes the receiving process to be told that it's input stream has been closed. However, that doesn't mean the processes input stream cannot be written to again, just that whichever process was writing to the input stream will not be writing to it again.

    The best way to deal with this is to setup a handler and let the OS know to invoke the handler whenever input is written to standard input. Normally you should avoid heavily relying on OS signal event handling as they are relatively expensive. However, copying a megabyte of text to following only produced two SIGIO events, so it's okay in this case.

    fancyecho.py

    import sys
    import os
    import signal
    import fcntl
    import threading
    
    io_event = threading.Event()
    
    # Event handlers should generally be as compact as possible.
    # Here all we do is notify the main thread that input has been received.
    def handle_io(signal, frame):
        io_event.set()
    
    # invoke handle_io on a SIGIO event
    signal.signal(signal.SIGIO, handle_io)
    # send io events on stdin (fd 0) to our process 
    assert fcntl.fcntl(0, fcntl.F_SETOWN, os.getpid()) == 0
    # tell the os to produce SIGIO events when data is written to stdin
    assert fcntl.fcntl(0, fcntl.F_SETFL, os.O_ASYNC) == 0
    
    print("pid is:", os.getpid())
    while True:
        data = sys.stdin.read()
        io_event.clear()
        print("got:", repr(data))
        io_event.wait()
    

    How you might use this toy program. Output has been cleaned up due to interleaving of input and output.

    $ echo test | python3 fancyecho.py &
    [1] 25487
    pid is: 25487
    got: 'test\n'
    $ echo data > /proc/25487/fd/0
    got: 'data\n'
    $
    
    0 讨论(0)
  • 2020-12-15 23:09

    I know this is an old thread but I stumbled upon the same problem and figured out that this was more to do with how the script was invoked rather than a problem with the script. At least in my case this turned out to be the problem with the 'system shell' on debian (ie: what /bin/sh is linked to -- this is what apache uses to execute the command that CustomLog pipes to). More info here: http://www.spinics.net/lists/dash/msg00675.html

    hth, - steve

    0 讨论(0)
  • 2020-12-15 23:09

    This works for me, code of /tmp/alog.py:

    #! /usr/bin/python
    
    import sys
    
    fout = open("/tmp/alog.log", "a")
    
    while True:
        dat = sys.stdin.readline()
        fout.write(dat)
        fout.flush()
    

    in http.conf:

    CustomLog "|/tmp/alog.py" combined
    

    The key is don't use

    for dat in sys.stdin:
    

    You will wait there get nothing. And for testing, remember fout.flush(), otherwise you may not see output. I test on fedora 15, python 2.7.1, Apache 2.2, not cpu load, alog.py will exists in memory, if you ps you can see it.

    0 讨论(0)
  • 2020-12-15 23:11

    Well i will stick now to these lines of code.

    #!/usr/bin/python
    import sys
    import time
    while 1:
        time.sleep(0.01)
        for line in sys.stdin:
            pass # do something useful
    

    If i don't use time.sleep, the script will create a too high load on cpu usage.

    If i use:

    for line in sys.stdin.readline():
    

    It will only parse one line in 0.01 seconds and the performance of the apache2 is really bad Thank you very much for your answers.

    best regards Abalus

    0 讨论(0)
  • 2020-12-15 23:12

    I have been having a similar problem where python waits for the sender (whether a user or another program) to close the stream before the loop starts executing. I had solved it, but it was clearly non pythonic as I had to resort to while True: and sys.stdin.readline()

    I eventually found a reference in a comment in another post to a module called io, which is an alternative to the standard file object. In Python 3 this is the default. From what I can make out Python 2 treats stdin like a normal file and not a stream.

    Try this, it worked for me:

    sys.stdin = io.open(sys.stdin.fileno())  # default is line buffering, good for user input
    
    for line in sys.stdin:
        # Do stuff with line
    
    0 讨论(0)
提交回复
热议问题