[Python编程(第4版)].(Programming.Python.4th.Edition).Mark.Lutz.文字版

(yzsuai) #1
Parent 6716 got [b'Spam 001'] at 1267996125.63
...etc.: Ctrl-C to exit...

Notice how the parent received a bytes string through the pipe. Raw pipes normally
deal in binary byte strings when their descriptors are used directly this way with the
descriptor-based file tools we met in Chapter 4 (as we saw there, descriptor read and
write tools in os always return and expect byte strings). That’s why we also have to
manually encode to bytes when writing in the child—the string formatting operation
is not available on bytes. As the next section shows, it’s also possible to wrap a pipe
descriptor in a text-mode file object, much as we did in the file examples in Chap-
ter 4, but that object simply performs encoding and decoding automatically on trans-
fers; it’s still bytes in the pipe.


Wrapping pipe descriptors in file objects


If you look closely at the preceding output, you’ll see that when the child’s delay counter
hits 004, the parent ends up reading two messages from the pipe at the same time; the
child wrote two distinct messages, but on some platforms or configurations (other than
that used here) they might be interleaved or processed close enough in time to be fetched
as a single unit by the parent. Really, the parent blindly asks to read, at most, 32 bytes
each time, but it gets back whatever text is available in the pipe, when it becomes
available.


To distinguish messages better, we can mandate a separator character in the pipe. An
end-of-line makes this easy, because we can wrap the pipe descriptor in a file object
with os.fdopen and rely on the file object’s readline method to scan up through the
next \n separator in the pipe. This also lets us leverage the more powerful tools of the
text-mode file object we met in Chapter 4. Example 5-20 implements this scheme for
the parent’s end of the pipe.


Example 5-20. PP4E\System\Processes\pipe2.py


same as pipe1.py, but wrap pipe input in stdio file object


to read by line, and close unused pipe fds in both processes


import os, time


def child(pipeout):
zzz = 0
while True:
time.sleep(zzz) # make parent wait
msg = ('Spam %03d\n' % zzz).encode() # pipes are binary in 3.X
os.write(pipeout, msg) # send to parent
zzz = (zzz+1) % 5 # roll to 0 at 5


def parent():
pipein, pipeout = os.pipe() # make 2-ended pipe
if os.fork() == 0: # in child, write to pipe
os.close(pipein) # close input side here
child(pipeout)


226 | Chapter 5: Parallel System Tools

Free download pdf