#!/usr/bin/env python3

import threading, time, math, multiprocessing

def fetch_data(source_id):
    """e.g., reading from file, doing math"""
    print(f"starting  fetch_data({source_id})")
#
    if (1==2): 
      time.sleep(1)   
    else:
      for _ in range(int(0.5e8)):
        math.sqrt(3.3 * 3.3)
#
    print(f"finishing fetch_data({source_id})\n")
    return

# ***
# *** main start
# ***
start_time = time.time()
nJobs = 3

print("# --- -------------------- ---")
print("# --- sequential execution ---")
print("# --- -------------------- ---")
for i in range(nJobs):
    fetch_data(i)

print(f"total time: {time.time() - start_time:.2f} seconds")

print()
print("# --- ------------------ ---")
print("# --- threaded execution ---")
print("# --- ------------------ ---")

start_time = time.time()
threads = []

# creating, storing, and starting threads
for i in range(nJobs):
    t = threading.Thread(target=fetch_data, args=(i,))
    threads.append(t)
    t.start()

# waiting for all threads to complete, before moving on
for t in threads:
    t.join()

print(f"total time: {time.time() - start_time:.2f} seconds")

print()
print("# --- ---------------- ---")
print("# --- multi-processing ---")
print("# --- ---------------- ---")

start_time = time.time()
processes = []

# create separate OS processes (bypassing the GIL)
for i in range(nJobs):
    p = multiprocessing.Process(target=fetch_data, args=(i,))
    processes.append(p)
    p.start()

# waiting for termination
for p in processes:
    p.join()

print(f"total time: {time.time() - start_time:.2f} seconds")
