为什么带有线程库的python脚本会占用100%的CPU?

问题描述

我有一些客户端脚本,该脚本在套接字上连接并等待数据。 在服务器端,有带有json包装器的ZeroMQ库。

因此,实际上,它是具有json数据格式的套接字连接。它是来自MetaTrader的股票市场数据。 所以我每分钟等待一条数据线。因为我的时间表是M1。

问题是为什么该脚本占用100%的CPU?

大多数情况下,它应该等待数据而不执行任何操作。我认为脚本中可能存在一些错误。但是我还没有技巧。 请告诉我我应该在哪里寻找问题。

这是一个脚本:



    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,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

解决方法

它是你的:

while True:
    pass
最后,

的重点是消耗CPU。使用time.sleep添加少量睡眠,CPU使用率将降低。或者,如果仅等待线程完成,只需加入它们,它将阻塞直到执行完成。

例如:

from time import sleep

while True:
    sleep(0.1)

或者如果您将线程对象收集在列表中,则应该:

for t in threads:
    t.join()

有关更多信息,请参考following post

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...