Skip to content

Instantly share code, notes, and snippets.

@markshannon
Created October 7, 2024 14:25
Show Gist options
  • Save markshannon/4f8820ef9c2b046cf86c98a507df4963 to your computer and use it in GitHub Desktop.
Save markshannon/4f8820ef9c2b046cf86c98a507df4963 to your computer and use it in GitHub Desktop.
1000 threads experiment

Case 1 -- Ultra contended

from threading import Thread
import time

class Counter():

    def __init__(self):
        self._counter = 0

    def increment(self):
        self._counter += 1

    def value(self):
        return self._counter

def task(counter):
    for _ in range(10_000):
        counter.increment()

def run():
    start = time.monotonic()
    counter = Counter()

    # create 1000 threads to increment the counter
    threads = [Thread(target=task, args=(counter,)) for _ in range(1_000)]

    # run all the threads
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()
    elapsed = time.monotonic() - start
    # We would like this to print exactly 10.0M
    print(f"{counter.value()/1_000_000}M")
    return elapsed

N = 10
times = [ run() for _ in range(10) ]
print()
print(f"Minimum: {min(times):.2f}s")
print(f"Maximum: {max(times):.2f}s")
print(f"Mean: {sum(times)/N:.2f}s")

Main

10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M

Minimum: 1.88s
Maximum: 2.36s
Mean: 2.07s

No-gil

0.038048M
0.015663M
0.013499M
0.013959M
0.013163M
0.013681M
0.014492M
0.013851M
0.013963M
0.015302M

Minimum: 235.67s
Maximum: 254.44s
Mean: 242.67s

Copy bytecodes

0.024776M
0.013753M
0.014106M
0.015259M
0.013617M
0.012738M
0.013892M
0.014315M
0.015506M
0.014675M

Minimum: 239.20s
Maximum: 277.06s
Mean: 258.71s

Case 2 -- No contention

from threading import Thread
import time

class Counter():

    def __init__(self):
        self._counter = 0

    def increment(self):
        self._counter += 1

    def value(self):
        return self._counter

def task(counter):
    for _ in range(10_000):
        counter.increment()


def run():
    start = time.monotonic()
    counters = [ Counter() for _ in range(1_000)]

    # create 1000 threads to increment the counter
    threads = [Thread(target=task, args=(counter,)) for counter in counters]

    # run all the threads
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()
    result = sum(counter.value() for counter in counters)
    elapsed = time.monotonic() - start
    # We would like this to print exactly 10.0M
    print(f"{result/1_000_000}M")
    return elapsed

N = 10
times = [ run() for _ in range(10) ]
print()
print(f"Minimum: {min(times):.2f}s")
print(f"Maximum: {max(times):.2f}s")
print(f"Mean: {sum(times)/N:.2f}s")

Main

10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M

Minimum: 1.39s
Maximum: 2.65s
Mean: 2.21s

No-gil

10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M

Minimum: 2.92s
Maximum: 3.01s
Mean: 2.95s

Copy bytecodes

10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M
10.0M

Minimum: 2.66s
Maximum: 2.89s
Mean: 2.80s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment