← 中文资源

简体中文版本

读写锁

读写锁允许多个读并发或单个写独占,为读多写少的共享状态提升吞吐。

阅读英文原文

概念定义

读写锁区分两种访问模式:任意数量的读者可同时持有锁,而写者需要独占访问并排斥所有读者。它刻画了数据被读取远多于被修改的常见模式。相对普通互斥锁,收益是读者之间的并发;代价是额外的簿记开销、在持续读压下写者可能饿死的风险,以及需要策略决定谁先获得锁。

为什么重要

许多共享结构——路由表、特性开关、缓存——在每次请求时被读取,却偶尔才被写入。普通互斥锁把这些读取串行化,随核心数与流量增长成为瓶颈。读写锁恢复并行的读吞吐,同时让更新保持安全,这往往就是“可扩展的锁”与“不可扩展的锁”之间的差别。

工程实践

仅用于确实读占主导的状态;当写很频繁时,普通互斥锁或无锁方案更简单也更快。优先选用公平或偏向写者的实现,使突发的读者不会饿死更新。绝不要就地升级读锁——应以写模式释放并重新获取,同时重新校验数据。可考虑使用写时复制的不可变快照,让读者在完全不需要锁的情况下继续。

代码示例

export type Release = () => void;

export class ReadWriteLock {
  private readers = 0;
  private writer = false;
  private waitingReaders: Array<() => void> = [];
  private waitingWriters: Array<() => void> = [];

  async acquireRead(): Promise<Release> {
    if (!this.writer && this.waitingWriters.length === 0) {
      this.readers += 1;
      return this.createReadRelease();
    }
    await new Promise<void>((resolve) => this.waitingReaders.push(resolve));
    return this.createReadRelease();
  }

  async acquireWrite(): Promise<Release> {
    if (!this.writer && this.readers === 0 && this.waitingWriters.length === 0) {
      this.writer = true;
      return this.createWriteRelease();
    }
    await new Promise<void>((resolve) => this.waitingWriters.push(resolve));
    return this.createWriteRelease();
  }

  private createReadRelease(): Release {
    let released = false;
    return () => {
      if (released) return;
      released = true;
      this.readers -= 1;
      if (this.readers === 0 && this.waitingWriters.length > 0) {
        this.writer = true;
        this.waitingWriters.shift()!();
      }
    };
  }

  private createWriteRelease(): Release {
    let released = false;
    return () => {
      if (released) return;
      released = true;
      this.writer = false;
      if (this.waitingWriters.length > 0) {
        this.writer = true;
        this.waitingWriters.shift()!();
        return;
      }
      const readers = this.waitingReaders.splice(0);
      this.readers += readers.length;
      for (const resolve of readers) resolve();
    };
  }

  get state(): {
    readers: number;
    writer: boolean;
    waitingReaders: number;
    waitingWriters: number;
  } {
    return {
      readers: this.readers,
      writer: this.writer,
      waitingReaders: this.waitingReaders.length,
      waitingWriters: this.waitingWriters.length,
    };
  }
}
package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func newHardenedServer(addr string) *http.Server {
	return &http.Server{
		Addr:              addr,
		ReadHeaderTimeout: 5 * time.Second, // 头部必须快速到达
		ReadTimeout:       10 * time.Second,
		WriteTimeout:      30 * time.Second,
		IdleTimeout:       120 * time.Second,

		MaxHeaderBytes: 1 << 20, // 头部上限 1MiB

		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.Method != http.MethodPost {
				w.Header().Set("Allow", http.MethodPost)
				http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
				return
			}
			fmt.Fprintln(w, "accepted")
		}),
	}
}

func main() {
	srv := newHardenedServer(":8080")
	log.Fatal(srv.ListenAndServe())
}