真的量一次
本节的东西:
model(tasks) 时间模型:每条线程 (算, 改) 两段耗时;粗锁全串行 = Σ(算+改),细锁算并行改串行 = max(算) + Σ改;交回 (粗, 细)
timed(fn, workers, work) 开 workers 条线程各跑 fn(work),交回耗时
coarse(work) sleep(work) 关在锁里再改 total;fine(work) sleep 在锁外,只把改关在锁里三条线程各 work 0.03 秒,粗锁版和细锁版各量一次,只比大小:
import threading
import time
class Counter:
def __init__(self):
self.n = 0
def inc(self):
tmp = self.n
time.sleep(0.001)
self.n = tmp + 1
class SafeCounter(Counter):
def __init__(self):
super().__init__()
self.lock = threading.Lock()
def inc(self):
with self.lock:
tmp = self.n
time.sleep(0.001)
self.n = tmp + 1
def hammer(counter, workers=2, times=30):
def job():
for _ in range(times):
counter.inc()
ts = [threading.Thread(target=job) for _ in range(workers)]
for t in ts:
t.start()
for t in ts:
t.join()
return counter.n
def probe(lock):
"""这把锁现在能不能立刻拿到?能就拿了再放回去,交回 True;拿不到交回 False。"""
if lock.acquire(blocking=False):
lock.release()
return True
return False
class Guard:
"""手写的 with 替身:进就 acquire,出就 release——不管是正常出还是异常出。"""
def __init__(self, lock):
self.lock = lock
def __enter__(self):
self.lock.acquire()
return self
def __exit__(self, exc_type, exc, tb):
self.lock.release()
return False
class Box:
"""有界队列:满了 put 等、空了 get 等;等的时候把锁交出去(wait_for 会放锁、醒来再拿回)。"""
def __init__(self, cap):
self.cap = cap
self.items = []
self.cond = threading.Condition()
def put(self, x):
with self.cond:
self.cond.wait_for(lambda: len(self.items) < self.cap)
self.items.append(x)
self.cond.notify_all()
def get(self):
with self.cond:
self.cond.wait_for(lambda: len(self.items) > 0)
x = self.items.pop(0)
self.cond.notify_all()
return x
def run_pc(cap, n):
"""一个生产者放 0..n-1,一个消费者取 n 个;交回消费者拿到的顺序。"""
box = Box(cap)
got = []
def producer():
for i in range(n):
box.put(i)
def consumer():
for _ in range(n):
got.append(box.get())
p = threading.Thread(target=producer, daemon=True)
c = threading.Thread(target=consumer, daemon=True)
p.start()
c.start()
p.join(timeout=2) # 写坏了的 get 会让生产者永远等——别把判题机拖死
c.join(timeout=2)
return got
class Gate:
"""最多 n 个同时在里面;顺便记下峰值(峰值计数器自己用一把锁保护)。"""
def __init__(self, n):
self.sem = threading.Semaphore(n)
self.lock = threading.Lock()
self.inside = 0
self.peak = 0
def __enter__(self):
self.sem.acquire()
with self.lock:
self.inside += 1
self.peak = max(self.peak, self.inside)
def __exit__(self, *a):
with self.lock:
self.inside -= 1
self.sem.release()
return False
def run_gate(n, workers, hold=0.03):
gate = Gate(n)
def job():
with gate:
time.sleep(hold)
ts = [threading.Thread(target=job) for _ in range(workers)]
for t in ts:
t.start()
for t in ts:
t.join()
return gate.peak
def model(tasks):
"""tasks: 每条线程 (算, 改) 两段耗时。粗锁:全串行 = Σ(算+改);细锁:算并行、改串行 = max(算) + Σ改。交回 (粗, 细)。"""
coarse = sum(a + b for a, b in tasks)
fine = max(a for a, b in tasks) + sum(b for a, b in tasks)
return coarse, fine
def timed(fn, workers, work=0.03):
"""开 workers 条线程各跑一次 fn(work),交回耗时。"""
ts = [threading.Thread(target=fn, args=(work,)) for _ in range(workers)]
t0 = time.perf_counter()
for t in ts:
t.start()
for t in ts:
t.join()
return time.perf_counter() - t0
LOCK = threading.Lock()
total = [0]
def coarse(work):
with LOCK:
time.sleep(work) # 耗时的「算」也关在锁里
total[0] += 1
def fine(work):
time.sleep(work) # 「算」在锁外
with LOCK:
total[0] += 1
TABLE = {
"python3": ("threading.Lock()", "lock.acquire()", "lock.release()", "with lock:"),
"c": ("pthread_mutex_t m", "pthread_mutex_lock(&m)", "pthread_mutex_unlock(&m)", "(没有:只能手动配对)"),
"cpp": ("std::mutex m", "m.lock()", "m.unlock()", "std::lock_guard<std::mutex> g(m)"),
}
def count_pairs(src):
"""C 源码里 lock 和 unlock 各出现几次。"""
return src.count("pthread_mutex_lock("), src.count("pthread_mutex_unlock(")
def find_leak(src):
"""按行扫 C 源码:拿了锁之后、放锁之前遇到 return,就是一条泄漏;交回泄漏所在的行号列表(从 1 起)。"""
held = False
leaks = []
for i, line in enumerate(src.split("\n"), 1):
s = line.strip()
if "pthread_mutex_lock(" in s:
held = True
elif "pthread_mutex_unlock(" in s:
held = False
elif "return" in s and held:
leaks.append(i)
return leaks
def guard_span(src):
"""C++ 源码:lock_guard 声明所在行到它所在花括号块结束的那一行(从 1 起),交回 (起, 止)。"""
lines = src.split("\n")
start = None
depth = 0
for i, line in enumerate(lines, 1):
if "lock_guard" in line and start is None:
start = i
depth = 0
if start is not None:
depth += line.count("{") - line.count("}")
if depth < 0:
return start, i
return start, len(lines)
tc = timed(coarse, 3)
tf = timed(fine, 3)
print(str(tc >= 0.09) + "/" + str(tf < 0.09) + "/" + str(tc > tf) + "/" + str(total[0]))
全部评论