Attempting two-way communication between Python2.7

2019-09-15 07:33发布

问题:

I'm using Python2.7, the SPARC ASP solver, and am running my code from the Ubuntu14.04 command line.

I'm trying to set up two-way communication between my Python code and my ASP (answer-set-programming) code. To do this I am sending queries from python to ASP, putting the ASP response into a fifo pipe, and in the python code the contents of the fifo is read into a string and that string is then written to a text file (this is so that I can check the text file to see if I'm getting the output I expect). However two problems are occuring: only part of the expected response appears in the text file, rather than the whole thing, and though my python code is in an infinite while loop it only appears to be running once. What is going wrong?

Unfortunately despite days of research and of asking smaller questions on stack overflow, and despite some very useful answers provided by the good people on this site, I am still getting nowhere and I'm not sure where in my code the problem lies. So I will post all of my code in the hopes that someone can help me resolve this problem once and for all.

My python code:

import sys
import os

while True:
    # communicate with ASP code
    try:
        sys.stdout.write('moveForward(turtlebot)\n')
    except KeyboardInterrupt:
        sys.stdout.write('moveForward(turtlebot)\n')
        sys.exit()

    # read back the output of the ASP code - should be '?- yes'
    try:
        fifo = os.open('fifo', os.O_RDONLY)
        string = os.read(fifo, 7)
        os.close(fifo)
    except KeyboardInterrupt:
        fifo = os.open('fifo', os.O_RDONLY)
        string = os.read(fifo, 7)
        os.close(fifo)
        sys.exit()  

    # write the latest output to the text file
    try:
        myfile = open("afile.txt", "w")
        myfile.write(string)
        myfile.close()
    except KeyboardInterrupt:
        myfile = open("afile.txt", "w")
        myfile.write(string)
        myfile.close()
        sys.exit()

My ASP code:

sorts
#robot = {turtlebot}.

predicates
moveForward(#robot).

rules
moveForward(turtlebot).

How I run my code from the command line:

mkfifo fifo
python test.py | java -jar sparc.jar aspfile.sp > fifo

What is happening:
After running my code, I check afile.txt to see what has been written. It is always just ?-, without the 'yes'. I can also tell that my python code is only running once because when I append to the text file instead of write, only one line is added each time I run my code. The output from the ASP solver should be ?- yes.

I doubt that the problem is in the ASP code, because if in the command line I type > sparc.out instead of > fifo (so that the output is put directly into a text file without going through the fifo first), the text file contains dozens of repetitions of ?- yes, which is what I would expect.

I need to figure out how to use a fifo instead of just writing output to a text file because constantly reading from / writing to a text file is too slow for the application my code is intended for (creating an action plan for a turtlebot; when I tested the text file version on the robot it constantly stopped and started because it paused every time it was reading from the text file).

I know that it's not very good form to just dump all my code into a post and say 'fix it for me!', but I'm at my wits end. If someone can help me get two-way communication working I would be so so grateful.

回答1:

Looks like a buffering problem to me. Using write does not mean that the other process has fully received your message. It just means that they have been copied to your internal write buffer. This buffer usually has 4k in size, and if it has not been completely filled nothing will be sent over to the other end. Similarly, when you read you cannot expect that 7 bytes are immediately available, as the other end may not have sent enough. It is very likely that SPARC just prints '?- ', which you immediately receive, and then waits for your input, which you have not sent yet. You can force to send the write buffer with a flush. You may also need to close stdout (which implicitly calls flush for sending a non-empty write buffer), as SPARC may wait for EOF before it starts with its computation.

Try to use sys.stdout.close (which calls flush) after sending your input, and use read in a loop until you receive 0 as return value, as there may be fewer than 7 bytes available at the moment.

Here is also a nice overview of stdio buffering: http://www.pixelbeat.org/programming/stdio_buffering/