How to handle data returned from thread functions in main function in Python

Viewed 56

I have a python script where I have created a thread. Below is the code snippet

stop_thread = False
get_data = False
status = ""
subject_id = ""


def get_data_function():
    global stop_thread
    global get_data 
    global status
    global subject_id

    while stop_thread is False:
        if get_data:
            # SOME CODE
            # SOME MORE CODE
            (status, subject_id) = tive.extract_data()

            get_data = False

        time.sleep(1)


def main():
    global stop_thread
    global get_data 
    global status
    global subject_id

    thread = Thread(target=get_data_function)
    thread.start()
    res_dict = dict()
    while True:
        # SOME CODE
        # SOME MORE CODE

        if some_condition:
            get_data = True

            res_dict['status'] = status
            res_dict['subject_id'] = subject_id

        # SOME CODE
        # SOME MORE CODE

In above code I have defined a thread and its function get_data_function(). This function calls tive.extract_data() which gives status, subject_id. I have defined these variables as global so that once we have the value of these variables , I can use it in main function.

In main function, after some_condition is True we need to get the values of status and subject_id so I set global variable get_data as True which enables the get_data_function main code and returns the data but the problem is that tive.extract_data() takes 2-3 secs to respond due to which res_dict['status'] = status and res_dict['subject_id'] = subject_id in main function gives error for that 2-3 secs and after that it starts working fine.

Is there any other way of handling the values of these variables in optimized way so that until we don't have values for these variables, we don't get errors. Please help. Thanks

2 Answers

I would define a thread class. I have bad experience using globals.

# ==================================================================================
class ThreadGetData(Thread):

    def __init__(self):
        super().__init__()

        self.stop_thread = False
        self.get_data = False
        self.status = ""
        self.subject_id = ""
        self.data_present = False

    # ------------------------------------------------------------------------------
    def get_data_function(self):

        if self.get_data:
            # SOME CODE
            # SOME MORE CODE
            (self.status, self.subject_id) = tive.extract_data()
            self.data_present = True
            self.get_data = False

        time.sleep(1)

    # ------------------------------------------------------------------------------
    def run(self):
        while not self.stop_thread:
            self.get_data_function()



# ==================================================================================
def main():

    thread = ThreadGetData()
    thread.start()

    res_dict = dict()
    while True:
        # SOME CODE
        # SOME MORE CODE

        if some_condition:
            thread.get_data = True

       if thread.data_present:
            res_dict['status'] = thread.status
            res_dict['subject_id'] = thread.subject_id
            self.data_present = False

        # SOME CODE
        # SOME MORE CODE

I would use Python 3's asyncio module, and use a coroutine instead of a thread. You can then move all of the operations that can be done before you need the value that the first coroutine returns into a second coroutine. Then, use asyncio.gather() to run both coroutines in parallel, waiting until both are finished.

Here is a simple example which demonstrates this pattern:

import asyncio
import datetime

async def main():
    print("Starting at " + str(datetime.datetime.now()))
    values = await asyncio.gather(get_value(3), do_other_stuff())
    print("Received: " + str(list(values)[0]))
    print("Finished at " + str(datetime.datetime.now()))

async def get_value(n):
    await asyncio.sleep(3)
    return n*10

async def do_other_stuff():
    print("doing things 1")
    await asyncio.sleep(1)
    print("doing things 2")
    await asyncio.sleep(2)
    print("doing things 3")


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
Related