core: many docstring updates and an example substitute for Channel

issue510
David Wilson 6 years ago
parent 84f75551a3
commit 120c667052

@ -0,0 +1,46 @@
# Wire up a ping/pong counting loop between 2 subprocesses.
from __future__ import print_function
import mitogen.core
import mitogen.select
@mitogen.core.takes_router
def ping_pong(control_sender, router):
with mitogen.core.Receiver(router) as recv:
# Tell caller how to communicate with us.
control_sender.send(recv.to_sender())
# Wait for caller to tell us how to talk back:
data_sender = recv.get().unpickle()
n = 0
while (n + 1) < 30:
n = recv.get().unpickle()
print('the number is currently', n)
data_sender.send(n + 1)
@mitogen.main()
def main(router):
# Create a receiver for control messages.
with mitogen.core.Receiver(router) as recv:
# Start ping_pong() in child 1 and fetch its sender.
c1 = router.local()
c1_call = c1.call_async(ping_pong, recv.to_sender())
c1_sender = recv.get().unpickle()
# Start ping_pong() in child 2 and fetch its sender.
c2 = router.local()
c2_call = c2.call_async(ping_pong, recv.to_sender())
c2_sender = recv.get().unpickle()
# Tell the children about each others' senders.
c1_sender.send(c2_sender)
c2_sender.send(c1_sender)
# Start the loop.
c1_sender.send(0)
# Wait for both functions to return.
mitogen.select.Select.all([c1_call, c2_call])

@ -714,7 +714,7 @@ class Message(object):
class Sender(object):
"""
Senders are used to send pickled messages to a handle in another context,
it is the inverse of :class:`mitogen.core.Sender`.
it is the inverse of :class:`mitogen.core.Receiver`.
Senders may be serialized, making them convenient to wire up data flows.
See :meth:`mitogen.core.Receiver.to_sender` for more information.
@ -785,10 +785,12 @@ class Receiver(object):
:param mitogen.core.Context respondent:
Context this receiver is receiving from. If not :data:`None`, arranges
for the receiver to receive a dead message if messages can no longer be
routed to the context, due to disconnection or exit.
routed to the context due to disconnection, and ignores messages that
did not originate from the respondent context.
"""
#: If not :data:`None`, a reference to a function invoked as
#: `notify(receiver)` when a new message is delivered to this receiver.
#: `notify(receiver)` when a new message is delivered to this receiver. The
#: function is invoked on the broker thread, therefore it must not block.
#: Used by :class:`mitogen.select.Select` to implement waiting on multiple
#: receivers.
notify = None
@ -830,6 +832,8 @@ class Receiver(object):
sender.send(line)
sender.close()
@mitogen.main()
def main(router):
remote = router.ssh(hostname='mainframe')
recv = mitogen.core.Receiver(router)
remote.call(deliver_monthly_report, recv.to_sender())
@ -840,7 +844,8 @@ class Receiver(object):
def _on_receive(self, msg):
"""
Callback from the Stream; appends data to the internal queue.
Callback registered for the handle with :class:`Router`; appends data
to the internal queue.
"""
_vv and IOLOG.debug('%r._on_receive(%r)', self, msg)
self._latch.put(msg)
@ -878,15 +883,15 @@ class Receiver(object):
If not :data:`None`, specifies a timeout in seconds.
:raises mitogen.core.ChannelError:
The remote end indicated the channel should be closed, or
communication with its parent context was lost.
The remote end indicated the channel should be closed,
communication with it was lost, or :meth:`close` was called in the
local process.
:raises mitogen.core.TimeoutError:
Timeout was reached.
:returns:
`(msg, data)` tuple, where `msg` is the :class:`Message` that was
received, and `data` is its unpickled data part.
:class:`Message` that was received.
"""
_vv and IOLOG.debug('%r.get(timeout=%r, block=%r)', self, timeout, block)
try:
@ -915,6 +920,13 @@ class Channel(Sender, Receiver):
A channel inherits from :class:`mitogen.core.Sender` and
`mitogen.core.Receiver` to provide bidirectional functionality.
This class is incomplete and obsolete, it will be removed in Mitogen 0.3.
Channels were an early attempt at syntax sugar. It is always easier to pass
around unidirectional pairs of senders/receivers, even though the syntax is
baroque:
.. literalinclude:: ../examples/ping_pong.py
Since all handles aren't known until after both ends are constructed, for
both ends to communicate through a channel, it is necessary for one end to
retrieve the handle allocated to the other and reconfigure its own channel

Loading…
Cancel
Save