Python get thread result

Threading Return Values in Python

You can return values from a thread via instance variables on the threading.Thread class or via global variables.

In this tutorial you will discover how to return values from a thread.

Need to Return Values From a Thread

A thread is a thread of execution in a computer program.

Every Python program has at least one thread of execution called the main thread. Both processes and threads are created and managed by the underlying operating system.

Sometimes we may need to create additional threads in our program in order to execute code concurrently.

Python provides the ability to create and manage new threads via the threading module and the threading.Thread class.

You can learn more about Python threads in the guude:

When using new threads, we may need to return a value from the thread to another thread, such as the main thread.

This may be for many reasons, such as:

  • The new thread loaded some data that needs to be returned.
  • The new thread calculated something that needs to be returned.
  • The new thread needs to share its state or status with another thread.

How can we return values from a thread in Python?

Run your loops using all CPUs, download my FREE book to learn how.

How to Return Values From a Thread

A thread cannot return values directly.

The start() method on a thread calls the run() method of the thread that executes our code in a new thread of execution. The run() method in turn may call a target function, if configured.

The start() method does not block, instead it returns immediately and does not return a value. The run method also does not return a value.

We can join a new thread from the current thread and block until the new thread terminates, but the join() method also does not return a value.

Instead, we must return values from a thread indirectly.

There are two main ways to return values from a thread, they are:

  • Extend threading.Thread and store data in instance variables.
  • Store data in global variables.

The preferred approach is to extend the threading.Thread class and store return data as instance variables.

This involves defining a new class that extends the threading.Thread and defines a constructor that calls the parent constructor.

The run() method can be defined that executes the custom code in a new thread and stores data as instance variables.

Источник

How to Return Values from a Thread

Summary: in this tutorial, you will learn how to return values from a child thread to the main thread by extending the threading.Thread class.

Читайте также:  Java web server class

When a Python program starts, it has a single thread called the main thread. Sometimes, you want to offload I/O tasks to new threads and execute them concurrently. Additionally, you may also want to get the return values from these threads from the main thread.

To return a value from a thread, you can extend the Thread class and store that value in the instance of the class.

The following example illustrates how to check a specified URL and return its HTTP status code in a separate thread:

from threading import Thread import urllib.request class HttpRequestThread(Thread): def __init__(self, url: str) -> None: super().__init__() self.url = url self.http_status_code = None self.reason = None def run(self) -> None: try: response = urllib.request.urlopen(self.url) self.http_status_code = response.code except urllib.error.HTTPError as e: self.http_status_code = e.code except urllib.error.URLError as e: self.reason = e.reason def main() -> None: urls = [ 'https://httpstat.us/200', 'https://httpstat.us/400' ] # create new threads threads = [HttpRequestThread(url) for url in urls] # start the threads [t.start() for t in threads] # wait for the threads to complete [t.join() for t in threads] # display the URLs with HTTP status codes [print(f' : ') for t in threads] if __name__ == '__main__': main() def main() -> None: urls = [ 'https://httpstat.us/200', 'https://httpstat.us/400' ] # create new threads threads = [HttpRequestThread(url) for url in urls] # start the threads [t.start() for t in threads] # wait for the threads to complete [t.join() for t in threads] # display the URLs with HTTP status codes [print(f' : ') for t in threads] Code language: Python (python)
ttps://httpstat.us/200: 200 https://httpstat.us/400: 400Code language: Python (python)

First, define the HttpRequestThread class that extends the Thread class:

class HttpRequestThread(Thread): # . Code language: Python (python)

Second, define the __init__() method that accepts a URL. Inside the __init__() method adds url , http_status_code , and reason instance variables. The http_status_code will store the status code of the url at the time of checking and the reason will store the error message in case an error occurs:

def __init__(self, url: str) -> None: super().__init__() self.url = url self.http_status_code = None self.reason = NoneCode language: Python (python)

Third, override the run() method that uses the urllib library to get the HTTP status code of the specified URL and assigns it to http_status_code field. If an error occurs, it assigns the error message to the reason field:

def run(self) -> None: try: response = urllib.request.urlopen(self.url) self.http_status_code = response.code except urllib.error.HTTPError as e: self.http_status_code = e.code except urllib.error.URLError as e: self.reason = e.reasonCode language: Python (python)

Later, we can access the url , http_status_code , and reason from the instance of the HttpRequestThread class.

Fourth, define the main() function that creates instances of the HttpRequestThread class, start the threads, wait for them to complete, and get the result from the instances:

def main() -> None: urls = [ 'https://httpstat.us/200', 'https://httpstat.us/400' ] # create new threads threads = [HttpRequestThread(url) for url in urls] # start the threads [t.start() for t in threads] # wait for the threads to complete [t.join() for t in threads] # display the URLs with HTTP status codes [print(f' : ') for t in threads]Code language: Python (python)

Summary

  • Extend the Thread class and set the instance variables inside the subclass to return the values from a child thread to the main thread.

Источник

How to return a result from a Python thread

Suppose you have a Python thread that runs your target function.

  • Simple scenario: That target function returns a result that you want to retrieve.
  • A more advanced scenario: You want to retrieve the result of the target function if the thread does not time out.

There are several ways to retrieve a value from a Python thread. You can use concurrent.futures , multiprocessing.pool.ThreadPool or just threading with Queue .

This post proposes an alternative solution that does not require any other package aside from threading .

The solution

If you don’t want to use anything else beside the threading module, the solution is simple:

  1. Extend the threading.Thread class and add a result member to your new class. Make sure to take into account positional and keyword arguments in the constructor.
  2. Override the base class’s run() method: in addition to running the target function as expected (with its args and kwargs intact), it has to store the target’s result in the new member result .
  3. Override the base class’s join() method: with args and kwargs intact, simply join() as in the base class but also return the result.
  4. Then when you instantiate your new thread class, intercept the result returned by join() .

Note the stress placed upon preserving the target’s positional and keyword arguments: this ensures that you can also join() the thread with a timeout, as you would a with a threading.Thread instance.

The following section illustrates these steps.

Implementation: ReturnValueThread class

Below, the class ReturnValueThread extends threading.Thread (lines 4-19).

  1. In the constructor, we declare a result member that will store the result returned by the target function (lines 6-8).
  2. We override the run() method by storing the result of the target in the result member (lines 10-16).
  3. We override the join() method such as to return the result member (lines 18-20).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
import threading import sys class ReturnValueThread(threading.Thread): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.result = None def run(self): if self._target is None: return # could alternatively raise an exception, depends on the use case try: self.result = self._target(*self._args, **self._kwargs) except Exception as exc: print(f'type(exc).__name__>: exc>', file=sys.stderr) # properly handle the exception def join(self, *args, **kwargs): super().join(*args, **kwargs) return self.result 

Usage example for ReturnValueThread

Here is how to use the ReturnValueThread class defined above. Imagine that the target functions both compute and return the square of the argument that gets passed to them:

  • square() returns the square of its argument instantly (lines 4-5);
  • think_about_square() returns the square of its argument after having… thought about it for a while (lines 8-10).

Why do we have two target functions in this example? Remember the scenarios mentioned at the beginning of this post:

  1. A simple scenario is to simply retrieve the value returned by the target function (lines 16-19);
  2. A more advanced scenario is to retrieve the value if the function finishes running before a specified timeout (lines 21-27).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
import time def square(x): return x ** 2 def think_about_square(x): time.sleep(x) return square(x) def main(): value = 3 thread1 = ReturnValueThread(target=square, args=(value,)) thread1.start() result = thread1.join() print(f'square(value>) = result>') thread2 = ReturnValueThread(target=think_about_square, args=(value,)) thread2.start() result = thread2.join(timeout=1) if thread2.is_alive(): print('Timeout in think_about_square') # properly handle timeout else: print(f'think_about_square(value>) = result>') if __name__ == '__main__': main() 

thread1 is the thread running square() (instant result, retrieved as expected). thread2 , on the other hand, runs think_about_square() , and it just so happens that it does not finish within the allotted time. We test whether the thread finished at line 24 via thread2.is_alive() .

Caveat

The more observant types have probably noticed that although ReturnValueThread returns the result of the target function, our thread2 in the above example (the thread that times out) does not exit cleanly. In fact, it runs until the sleep() ends. In a previous post we have seen how to exit a Python thread cleanly. Another solution is to use a process instead of a thread, but this comes with its own set of complications. The most notable difficulty is the fact that, unlike threads, processes run in separate memory spaces, which tends to complicate things since resources now have to be shared.

Further reading

  • How to exit a Python thread cleanly (using a threading event)
  • Multiprocessing in Python with shared resources
  • concurrent.futures (Python documentation)
  • multiprocessing.pool.ThreadPool (Python documentation)
  • threading (Python documentation)
  • Queue (Python documentation)

Источник

Оцените статью