Is this multi-threaded function asynchronous

Viewed 2243

I'm afraid I'm still a bit confused (despite checking other threads) whether:

  • all asynchronous code is multi-threaded
  • all multi-threaded functions are asynchronous

My initial guess is no to both and that proper asynchronous code should be able to run in one thread - however it can be improved by adding threads for example like so:

enter image description here

So I constructed this toy example:

from threading import *
from queue import Queue
import time

def do_something_with_io_lag(in_work):
    out = in_work
    # Imagine we do some work that involves sending
    # something over the internet and processing the output
    # once it arrives
    time.sleep(0.5) # simulate IO lag
    print("Hello, bee number: ",
          str(current_thread().name).replace("Thread-",""))

class WorkerBee(Thread):
    def __init__(self, q):
        Thread.__init__(self)
        self.q = q

    def run(self):
        while True:
            # Get some work from the queue
            work_todo = self.q.get()
            # This function will simiulate I/O lag
            do_something_with_io_lag(work_todo)
            # Remove task from the queue
            self.q.task_done()

if __name__ == '__main__':
    def time_me(nmbr):
        number_of_worker_bees = nmbr
        worktodo = ['some input for work'] * 50

        # Create a queue
        q = Queue()
        # Fill with work
        [q.put(onework) for onework in worktodo]
        # Launch processes
        for _ in range(number_of_worker_bees):
            t = WorkerBee(q)
            t.start()
        # Block until queue is empty
        q.join()

    # Run this code in serial mode (just one worker)
    %time time_me(nmbr=1)
    # Wall time: 25 s
    # Basically 50 requests * 0.5 seconds IO lag
    # For me everything gets processed by bee number: 59

    # Run this code using multi-tasking (launch 50 workers)
    %time time_me(nmbr=50)
    # Wall time: 507 ms
    # Basically the 0.5 second IO lag + 0.07 seconds it took to launch them
    # Now everything gets processed by different bees

Is it asynchronous?

To me this code does not seem asynchronous because it is Figure 3 in my example diagram. The I/O call blocks the thread (although we don't feel it because they are blocked in parallel).

However, if this is the case I am confused why requests-futures is considered asynchronous since it is a wrapper around ThreadPoolExecutor:

with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
    future_to_url = {executor.submit(load_url, url, 10): url for url in     get_urls()}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()

Can this function on just one thread?

Especially when compared to asyncio, which means it can run single-threaded

There are only two ways to have a program on a single processor do “more than one thing at a time.” Multi-threaded programming is the simplest and most popular way to do it, but there is another very different technique, that lets you have nearly all the advantages of multi-threading, without actually using multiple threads. It’s really only practical if your program is largely I/O bound. If your program is processor bound, then pre-emptive scheduled threads are probably what you really need. Network servers are rarely processor bound, however.

2 Answers
Related