0

i have some client script, that connects on socket and wait for data. On server side there is ZeroMQ lib with json wrapper.

So, actually, its a socket connection with json data format. Its a stockmarket data from metatrader. So i wait a one data line per minute. As my timeframe is M1.

The question is why this script eats 100% cpu?

Most of time it should wait for data and do nothing. I thing there might be some mistake in a script. But i have no skill yet in threding. Please tell me where i should look for a problem.

here is a script:



    import zmq
    import threading
    class MTraderAPI:
        def __init__(self, host=None):
            self.HOST = host or 'localhost'
            self.SYS_PORT = 15555       # REP/REQ port
            self.DATA_PORT = 15556      # PUSH/PULL port
            self.LIVE_PORT = 15557      # PUSH/PULL port
            self.EVENTS_PORT = 15558    # PUSH/PULL port
    
            # ZeroMQ timeout in seconds
            sys_timeout = 1
            data_timeout = 10
    
            # initialise ZMQ context
            context = zmq.Context()
    
            # connect to server sockets
            try:
                self.sys_socket = context.socket(zmq.REQ)
                # set port timeout
                self.sys_socket.RCVTIMEO = sys_timeout * 1000
                self.sys_socket.connect('tcp://{}:{}'.format(self.HOST, self.SYS_PORT))
    
                self.data_socket = context.socket(zmq.PULL)
                # set port timeout
                self.data_socket.RCVTIMEO = data_timeout * 1000
                self.data_socket.connect('tcp://{}:{}'.format(self.HOST, self.DATA_PORT))
            except zmq.ZMQError:
                raise zmq.ZMQBindError("Binding ports ERROR")
    
        def _send_request(self, data: dict) -> None:
            """Send request to server via ZeroMQ System socket"""
            try:
                self.sys_socket.send_json(data)
                msg = self.sys_socket.recv_string()
                # terminal received the request
                assert msg == 'OK', 'Something wrong on server side'
            except AssertionError as err:
                raise zmq.NotDone(err)
            except zmq.ZMQError:
                raise zmq.NotDone("Sending request ERROR")
    
        def _pull_reply(self):
            """Get reply from server via Data socket with timeout"""
            try:
                msg = self.data_socket.recv_json()
            except zmq.ZMQError:
                raise zmq.NotDone('Data socket timeout ERROR')
            return msg
    
        def live_socket(self, context=None):
            """Connect to socket in a ZMQ context"""
            try:
                context = context or zmq.Context.instance()
                socket = context.socket(zmq.PULL)
                socket.connect('tcp://{}:{}'.format(self.HOST, self.LIVE_PORT))
            except zmq.ZMQError:
                raise zmq.ZMQBindError("Live port connection ERROR")
            return socket
    
        def streaming_socket(self, context=None):
            """Connect to socket in a ZMQ context"""
            try:
                context = context or zmq.Context.instance()
                socket = context.socket(zmq.PULL)
                socket.connect('tcp://{}:{}'.format(self.HOST, self.EVENTS_PORT))
            except zmq.ZMQError:
                raise zmq.ZMQBindError("Data port connection ERROR")
            return socket
    
        def construct_and_send(self, **kwargs) -> dict:
            """Construct a request dictionary from default and send it to server"""
    
            # default dictionary
            request = {
                "action": None,
                "actionType": None,
                "symbol": None,
                "chartTF": None,
                "fromDate": None,
                "toDate": None,
                "id": None,
                "magic": None,
                "volume": None,
                "price": None,
                "stoploss": None,
                "takeprofit": None,
                "expiration": None,
                "deviation": None,
                "comment": None
            }
    
            # update dict values if exist
            for key, value in kwargs.items():
                if key in request:
                    request[key] = value
                else:
                    raise KeyError('Unknown key in **kwargs ERROR')
    
            # send dict to server
            self._send_request(request)
    
            # return server reply
            return self._pull_reply()
    
    api = MTraderAPI()
    print(api.construct_and_send(action="CONFIG", symbol="XBRUSD.c", chartTF="TICK"))
    
    def _t_livedata():
        socket = api.live_socket()
        while True:
            try:
                last_candle = socket.recv_json()
            except zmq.ZMQError:
                raise zmq.NotDone("Live data ERROR")
            print(last_candle)
    
    
    def _t_streaming_events():
        socket = api.streaming_socket()
        while True:
            try:
                trans = socket.recv_json()
                request, reply = trans.values()
            except zmq.ZMQError:
                raise zmq.NotDone("Streaming data ERROR")
            print(request)
            print(reply)
    
    
    
    t = threading.Thread(target=_t_livedata, daemon=True)
    t.start()
    
    t = threading.Thread(target=_t_streaming_events, daemon=True)
    t.start()
    
    while True:
        pass

navy
  • 159
  • 9

1 Answers1

2

Its your:

while True:
    pass

in the end - The whole point of it is to consume CPU. Add a small sleep using time.sleep and the CPU usage will decrease. Or if you only wait for the threads to finish, just join them, it will block until their execution is finished.

e.g:

from time import sleep

while True:
    sleep(0.1)

or if you collect your threads object in a list, you should:

for t in threads:
    t.join()

Refer to the following post for more information.

Or Y
  • 2,088
  • 3
  • 16
  • just realized it and try sleep(0.01) now its no load at all. Is it a proper method of threading usage? i mean to fill an empty loop with a minimal delay. Or its just a some workaround and there might be a smart pythonic way? – navy Sep 06 '20 at 12:24
  • @navy check the second option of joining the threads, this is best solution if you are waiting for your threads to finish – Or Y Sep 06 '20 at 12:57