Multithreaded lookup performance: measure throughput of concurrent lookups.
()
| 21 | |
| 22 | |
| 23 | def test_multithreaded_lookup(): |
| 24 | """Multithreaded lookup performance: measure throughput of concurrent lookups.""" |
| 25 | # Prepare dataset |
| 26 | size = 100_000 |
| 27 | keys = list(range(size)) |
| 28 | random.shuffle(keys) |
| 29 | tree = BPlusTree(capacity=128) |
| 30 | for key in keys: |
| 31 | tree[key] = key * 2 |
| 32 | |
| 33 | lookup_keys = random.sample(keys, min(10_000, size)) |
| 34 | |
| 35 | def worker(iterations): |
| 36 | for _ in range(iterations): |
| 37 | for k in lookup_keys: |
| 38 | _ = tree[k] |
| 39 | |
| 40 | thread_count = 4 |
| 41 | iterations = 5 |
| 42 | |
| 43 | gc.collect() |
| 44 | gc.disable() |
| 45 | threads = [] |
| 46 | start = time.perf_counter() |
| 47 | for _ in range(thread_count): |
| 48 | t = threading.Thread(target=worker, args=(iterations,)) |
| 49 | t.start() |
| 50 | threads.append(t) |
| 51 | for t in threads: |
| 52 | t.join() |
| 53 | total_time = time.perf_counter() - start |
| 54 | gc.enable() |
| 55 | |
| 56 | total_ops = thread_count * iterations * len(lookup_keys) |
| 57 | ns_per_op = total_time * 1e9 / total_ops |
| 58 | ops_per_sec = total_ops / total_time |
| 59 | print( |
| 60 | f"Threads: {thread_count}, Multithreaded lookup: {ns_per_op:.1f} ns/op ({ops_per_sec:.0f} ops/sec)" |
| 61 | ) |