Goroutines in Karel

Goroutines in Python

A goroutine is a lightweight thread of execution. Here’s how a similar concept can be implemented in Python using threads.

import threading
import time

def f(from_):
    for i in range(3):
        print(f"{from_} : {i}")

def main():
    # Suppose we have a function call f(s). Here’s how we’d call that in the usual way, running it synchronously.
    f("direct")

    # To invoke this function in a thread, use threading.Thread. This new thread will execute concurrently with the calling one.
    thread = threading.Thread(target=f, args=("thread",))
    thread.start()

    # You can also start a thread for an anonymous function call.
    thread2 = threading.Thread(target=lambda: print("going"))
    thread2.start()

    # Our two function calls are running asynchronously in separate threads now. Wait for them to finish.
    thread.join()
    thread2.join()
    
    print("done")

if __name__ == "__main__":
    main()

Explanation:

  1. Define the function f:

    def f(from_):
        for i in range(3):
            print(f"{from_} : {i}")
  2. Calling the function synchronously:

    f("direct")
  3. Starting a new thread:

    thread = threading.Thread(target=f, args=("thread",))
    thread.start()
  4. Starting a thread for an anonymous function call:

    thread2 = threading.Thread(target=lambda: print("going"))
    thread2.start()
  5. Waiting for threads to finish:

    thread.join()
    thread2.join()
  6. Printing “done”:

    print("done")

Running the program:

When you run this program, you will see the following output, which can be interleaved because threads are executed concurrently by the Python runtime.

$ python goroutines.py
direct : 0
direct : 1
direct : 2
thread : 0
going
thread : 1
thread : 2
done

Next, we’ll look at a complement to threads in concurrent Python programs: async/await and asyncio.