From 9ac8dd1fec86d880eaa828f05510e1f9bcd1f763 Mon Sep 17 00:00:00 2001 From: Britney Whittington Date: Wed, 13 May 2026 09:26:41 -0700 Subject: [PATCH 1/3] Add bwhitt7 to the README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 44e0723..0fa742e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Python Performance Lab: Sharpening Your Instincts +This is bwhitt7's fork. + A PyCon US 2026 hands-on tutorial. You optimize intentionally slow Python code across three rounds plus a team challenge, measuring every change with [CodSpeed](https://codspeed.io). From 3112d11ee24d7500bd4e33cd15b6b53337638c62 Mon Sep 17 00:00:00 2001 From: Britney Whittington Date: Wed, 13 May 2026 12:22:52 -0700 Subject: [PATCH 2/3] Add ThreadPoolExecutor to 3_dna solution --- rounds/3_dna/solution.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/rounds/3_dna/solution.py b/rounds/3_dna/solution.py index 8b917da..ab11afa 100644 --- a/rounds/3_dna/solution.py +++ b/rounds/3_dna/solution.py @@ -6,12 +6,45 @@ """ from .baseline import find_matches as _baseline +from concurrent.futures import ThreadPoolExecutor +import threading +def _thread_worker(pattern_str: str, record: str, matches, lock:threading.Lock): + if not record.strip(): + return + lines = record.split("\n") + record_id = lines[0].strip() + sequence = "".join(lines[1:]).replace(" ", "") + positions: list[int] = [] + start = 0 + while True: + pos = sequence.find(pattern_str, start) + if pos == -1: + break + positions.append(pos) + start = pos + 1 + + if positions: + with lock: + matches[record_id] = positions def find_matches(fasta_path: str, pattern: bytes) -> list[tuple[str, list[int]]]: """Find every FASTA record whose sequence contains ``pattern``. Returns ``[(record_id, [positions...]), ...]`` in file order. """ - # TODO: remove this delegation and write your own implementation here. - return _baseline(fasta_path, pattern) + pattern_str = pattern.decode("ascii") + with open(fasta_path, "r") as f: + text = f.read() + + matches: dict[str, list[int]] = {} + + lock = threading.Lock() + with ThreadPoolExecutor(max_workers=5) as executor: + executor.map(lambda args: _thread_worker(*args), + [ + (pattern_str, record, matches, lock) + for record in text.split(">") + ]) + matches = dict(sorted(matches.items())) + return [(k,v) for k,v in matches.items()] \ No newline at end of file From 8bd033df4ed27ad5cb782ff24e334f279d959b21 Mon Sep 17 00:00:00 2001 From: Britney Whittington Date: Wed, 13 May 2026 12:25:37 -0700 Subject: [PATCH 3/3] Auto detect CPU avaliable --- rounds/3_dna/solution.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rounds/3_dna/solution.py b/rounds/3_dna/solution.py index ab11afa..7e2739d 100644 --- a/rounds/3_dna/solution.py +++ b/rounds/3_dna/solution.py @@ -8,6 +8,7 @@ from .baseline import find_matches as _baseline from concurrent.futures import ThreadPoolExecutor import threading +import os def _thread_worker(pattern_str: str, record: str, matches, lock:threading.Lock): if not record.strip(): @@ -40,7 +41,7 @@ def find_matches(fasta_path: str, pattern: bytes) -> list[tuple[str, list[int]]] matches: dict[str, list[int]] = {} lock = threading.Lock() - with ThreadPoolExecutor(max_workers=5) as executor: + with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor: executor.map(lambda args: _thread_worker(*args), [ (pattern_str, record, matches, lock)