Performance in python 3.9 and difference between multiprocTCPBase and multiporcQueueBase.
FillyHolly opened this issue · comments
Hello! I'm interested in several questions:
-
Is this project currently supported?
-
Does this project work on python 3.9?
-
I have code. And I don't understand multiprocTCPBase and multiprocQueueBase work. When using multiprocTCPBase the work does not terminate when ActorExitRequest occurs. But when use multiprocQueueBase, the whole process ends and the actor stop working. Why is that?
3.1) Option using multiprocTCPBase
from thespian.actors import *
from time import sleep
class Connect(object):
def __init__(self, ipAddress, socketNum):
self.ipAddress = ipAddress
self.socketNum = socketNum
class MeasureValue(object):
def __init__(self, measureCmd):
self.measureCmd = measureCmd
def __str__(self): return self.measureCmd
class CheckCMD(object):
def __init__(self, disableCmd):
self.disableCmd = disableCmd
def __str__(self): return self.disableCmd
class Connection(ActorTypeDispatcher):
def receiveMsg_Connect(self, message, sender):
self.ipAddress = message.ipAddress
self.socketNum = message.socketNum
print('Connect to ', self.ipAddress, self.socketNum)
def receiveMsg_MeasureValue(self, message, sender):
answer = 'Voltage, Current, Power'
self.meas = message
print(self._sendSetCommand(self.meas, answer))
sleep(1)
self.send(self.myAddress, self.meas)
def _sendSetCommand(self, cmd, answer):
return {'Voltage': 0, 'Current': 0, 'Power': 0}
def receiveMsg_CheckCMD(self, message, sender):
print(message)
def main():
asys = ActorSystem('multiprocTCPBase')
try:
conn = asys.createActor(Connection)
asys.tell(conn, Connect('111.11.11.111', 1001))
sleep(1)
asys.tell(conn, MeasureValue(':MEASure1?'))
sleep(3)
asys.tell(conn, CheckCMD('someCMD'))
sleep(3)
asys.tell(conn, ActorExitRequest())
finally:
asys.shutdown()
if __name__ == '__main__':
main()
3.2) Option using multiprocQueueBase
from thespian.actors import *
from time import sleep
class Connect(object):
def __init__(self, ipAddress, socketNum):
self.ipAddress = ipAddress
self.socketNum = socketNum
class MeasureValue(object):
def __init__(self, measureCmd):
self.measureCmd = measureCmd
def __str__(self): return self.measureCmd
class CheckCMD(object):
def __init__(self, disableCmd):
self.disableCmd = disableCmd
def __str__(self): return self.disableCmd
class Connection(ActorTypeDispatcher):
def receiveMsg_Connect(self, message, sender):
self.ipAddress = message.ipAddress
self.socketNum = message.socketNum
print('Connect to ', self.ipAddress, self.socketNum)
def receiveMsg_MeasureValue(self, message, sender):
answer = 'Voltage, Current, Power'
self.meas = message
print(self._sendSetCommand(self.meas, answer))
sleep(1)
self.send(self.myAddress, self.meas)
def _sendSetCommand(self, cmd, answer):
return {'Voltage': 0, 'Current': 0, 'Power': 0}
def receiveMsg_CheckCMD(self, message, sender):
print(message)
def main():
asys = ActorSystem('multiprocQueueBase')
try:
conn = asys.createActor(Connection)
asys.tell(conn, Connect('111.11.11.111', 1001))
sleep(1)
asys.tell(conn, MeasureValue(':MEASure1?'))
sleep(3)
asys.tell(conn, CheckCMD('someCMD'))
sleep(3)
asys.tell(conn, ActorExitRequest())
finally:
asys.shutdown()
if __name__ == '__main__':
main()
- This is an open source project, so there is no official "support" provided. I am happy to answer questions and provide assistance where I can, but no guarantees or warrantees are provided.
- It does. Do you have information to the contrary?
- I did not do a detailed comparison, so I'm assuming your two code bases are identical with the exception of the argument to
ActorSystem
in themain
function. Looking over both, I see thatreceiveMsg_MeasureValue
in theConnection
actor will sleep (Actors are not recommended to sleep) and then sends itself the original message it received. This is essentially an infinite loop. More below:
Actors are not recommended to sleep, because this prevents them from handling any other messages. In the case of a multiprocTCPBase, the socket activity to send and receive messages is handled via non-blocking asynchronous code that runs when not running the receiveMessage
code. Since the sleep causes the the Actor to block in the receiveMessage
for most of the execution, the Actor does not have much opportunity to do the background processing.
For the multiprocTCPBase, this is probably filling the outbound and inbound TCP socket attempts, but the sleep is preventing them from being processed asynchronously and completing the receive of the CheckCMD
and the ActorExitRequest
. A transmit to self.myAddress
bypasses any actual socket sending and is just placed back on the receive queue, which in this case immediately re-enters the receiveMessage
handling, further preventing processing of the socket activity.
For the multiprocQueueBase, the send isn't asynchronous as it is for the multprocTCPBase, but the self-send bypasses the queueing and re-enters the receiveMessage, so it's also unlikely it is handling the CheckCMD
and ActorExitRequest
messages (although I cannot quite tell what exactly is happening from your description).
The general guide is that an Actor should not perform blocking operations in its receiveMessage
method because that will prevent it from performing normal Actor-related activities. If you would like to schedule future activity in an Actor, I would recommend using the self.wakeupAfter()
method to schedule that future activity and then directly returning from the receiveMessage
method.
Closing this because there was no followup so I'm assuming I answered your questions satisfactorily. Please re-open or post another issue if you still have questions or problems.