简体   繁体   中英

Very Slow Binary File Download in Multithreaded Python Program on Raspberry Pi

I'm writing a multi-threaded Python application on a Raspberry Pi 4 that occasionally needs to download binary files on the order of ~200 kilobytes from a server, which during testing is my laptop on the local network. I've verified that these files are served by my laptop in about a second using Curl or a Python 3 CLI requests.get call on the RPi, but inside my application the requests download call hangs for at least 2 minutes before completing. The affected code is here:

# requests current composite from server 
# args:     timestamp: timestamp of last update
# returns:  SUCCESS_RETURN if updated, NONE_RETURN otherwise, OFFLINE_RETURN on failure to connect

def getcomposite(self, timestamp=None):
    try:
        self.slplogger.info("Downloading composite for timestamp %s" % (dt.utcfromtimestamp(timestamp).strftime("%Y-%m-%d-%H:%M:%S") if timestamp else "None"))

        # HANGS HERE
        compositeresp = requests.post(SERVER_URL + "getcomposite", data={'mac' : self.mac, 'timestamp' : timestamp})

        self.slplogger.info("Downloaded new composite: %s" % str(compositeresp.text[:min(10, len(compositeresp.text))]))

        if compositeresp.text != NONE_RETURN and compositeresp.content:
            with self.compositelock:
                self.compositedata = np.load(BytesIO(compositeresp.content), allow_pickle=False)
                # compute new input norm for adding subsequent input
                self.compositenorm = np.mean(self.compositedata[:]['value'], dtype=int)
                self.emptycomposite = False
                self.slplogger.info("Set new composite: %s" % str(self.compositedata[:min(10, len(self.compositedata))]))
            return SUCCESS_RETURN
        return FAILURE_RETURN
    except requests.exceptions.ConnectionError:

        self.slplogger.info("Composite download failed. Unable to connect to server")
        return OFFLINE_RETURN

The non-daemon thread that calls this method is defined here (COMPOSITE_POLL_INTERVAL is 2 seconds):

# --------------------------------------------------------------------
#   CompositePollingThread - Thread superclass that periodically 
#   polls strangeloop server for new additions to the composite loop
# --------------------------------------------------------------------

class CompositePollingThread(Thread):

    # overloaded Thread constructor
    # args:     pedal: parent Pedal object that instantiated this thread

    def __init__(self, pedal):
        Thread.__init__(self)
        self.stop = Event()
        self.pedal = pedal
        self.timestamp = None

        self.pedal.slplogger.debug("Initialized composite polling thread")

    # main thread execution loop

    def run(self):

        self.pedal.slplogger.debug("Started composite polling thread")

        while self.pedal.running:
            time.sleep(COMPOSITE_POLL_INTERVAL)

            # timestamp to determine whether any new data needs to be downloaded
            if not self.pedal.recording and self.pedal.getcomposite(timestamp=self.timestamp) == SUCCESS_RETURN:
                self.timestamp = dt.utcnow().timestamp()

                self.pedal.slplogger.debug("Downloaded new composite at %s" % dt.utcfromtimestamp(self.timestamp).strftime("%Y-%m-%d-%H:%M:%S"))

        self.pedal.slplogger.debug("Ended composite polling thread")

I'm assuming this slow download is caused by a threading issue in the program. It's also tasked with processing real-time input, which takes up the majority of the CPU. Is there anything I can do to improve this download speed? Is there a way to give the thread more priority, or should I switch to the multiprocessing module to take advangage of the RPi 4's multiple cores?

In the end, the issue was on the server. I changed the endpoint response from a "flask.send_file" with a BytesIO wrapper around the data I needed to a simple flask.Response object with the data as the text (similar to Serve image stored in SQLAlchemy LargeBinary column ), and now it downloads in less than ten seconds. I don't know why the download took so long before only when accessed through the program (as opposed to CLI requests), but that change took care of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM