Cách Mẫu Intertangle Hình Thành
Hai hệ thống con bắt đầu như các mô-đun độc lập. Theo thời gian, mỗi hệ thống tích lũy một trường trên god-object được chia sẻ: một cấu trúc config toàn cục, một singleton manager, một lớp tĩnh. Mỗi lần thêm: đúng khi xét riêng lẻ. Sự ghép nối: vô hình trong kiểm thử quy mô nhỏ.
Ba môi trường mà điều này đã trở nên cố định:
VLC media player. Audio, video, & playlist chia sẻ một khóa duy nhất bảo vệ trạng thái trình phát toàn cục. Yêu cầu skip-to-timestamp thu được khóa, thay đổi vị trí phát lại, & xóa bộ đệm âm thanh. Hệ thống con video, đang chờ cùng khóa, bị treo. Hệ thống con playlist, cũng đang chờ, không thể prefetch. Kết quả: ba hệ thống con độc lập được tuần tự hóa qua một đối tượng trạng thái duy nhất. Chi phí hiệu năng: tranh chấp khóa O(N) trong đó N = số lượng hệ thống con, tất cả tỷ lệ với độ trễ hoạt động.
Vòng lặp sự kiện Redis. AOF fsync (ghi đĩa), sao chép (ghi mạng) và thực thi lệnh (CPU) chia sẻ cùng một vòng lặp sự kiện đơn luồng. Mỗi thành phần đều đúng khi hoạt động riêng lẻ. Một fsync chậm sẽ làm đình trệ việc thực thi lệnh. Độ trễ sao chép tăng lên khi có tải ghi lớn. Điểm kết nối: một ngữ cảnh thực thi duy nhất được chia sẻ bởi các thao tác có đặc tính độ trễ khác nhau.
LevelDB VersionSet. Đường ghi (xả memtable) và nén nền chia sẻ khóa VersionSet. Một tác vụ nén giữ khóa trong hàng chục mili giây. Đường ghi bị đình trệ. Cả hai thao tác đều cần thiết. Điểm kết nối mang tính cấu trúc, không phải về thời gian.
Sự khác biệt then chốt
Một Intertangle có sự kết nối mang tính cấu trúc, không phải vấn đề về thời gian. Một race condition: hai luồng truy cập trạng thái chia sẻ mà không có đồng bộ hóa. Cách khắc phục: thêm mutex.
Một Intertangle: hai hệ thống con chia sẻ trạng thái theo thiết kế. Thêm mutex không khắc phục được sự kết nối; nó chỉ tuần tự hóa quyền truy cập. Các hệ thống con vẫn chia sẻ trạng thái. Điểm nghẽn trở nên chặt chẽ hơn.
Việc thêm mutex vào một Intertangle VLC làm tình hình tệ hơn: giờ thì audio, video và danh sách phát đều phải chờ một khóa duy nhất. Cách khắc phục cấu trúc: cấp cho mỗi hệ thống con trạng thái riêng của nó. Phase snapshot: đóng băng một bản sao của trạng thái chia sẻ tại ranh giới pha, cho phép mỗi hệ thống con đọc bản sao độc lập, sau đó hợp nhất các thay đổi trở lại khi kết thúc.
Cấu trúc so với Thời gian
Câu hỏi chẩn đoán then chốt cho một Intertangle: việc thêm mutex có khắc phục được không, hay sẽ làm tình hình tệ hơn?
Một điều kiện đua: thêm mutex sẽ sửa được. Thứ tự truy cập đúng sẽ loại bỏ sự hỏng hóc.
Một Intertangle: thêm mutex sẽ tuần tự hóa quyền truy cập nhưng vẫn giữ nguyên sự liên kết cấu trúc. Các hệ thống con vẫn chia sẻ trạng thái. Dưới tải, chúng vẫn chặn lẫn nhau. Nút thắt hẹp hơn.
Cách tìm một Intertangle
Ba tín hiệu phát hiện:
1. Các trường có thể thay đổi được chia sẻ giữa các hệ thống con. Một god-object có các trường được nhiều hệ thống con đọc & ghi. Nếu việc xóa quyền truy cập trường của một hệ thống con làm hỏng hệ thống con khác, chúng đang chia sẻ trạng thái.
2. Một mutex duy nhất bảo vệ các hoạt động không liên quan. Một khóa bảo vệ đồng thời flush âm thanh VÀ giải mã video VÀ nạp danh sách phát: ba hệ thống con có đặc điểm độ trễ khác nhau, tất cả đều phải chờ lẫn nhau. Dấu hiệu: các hoạt động không liên quan nằm dưới cùng một tên khóa.
3. Hiệu năng suy giảm khi tăng tải. Độ trễ của thao tác A tăng khi thao tác B chạy đồng thời, dù A & B dường như độc lập. Chúng không độc lập: chúng chia sẻ trạng thái.
Giải pháp Phase-Snapshot
Mẫu phase snapshot:
# TRƯỚC: các hệ thống con đọc và ghi trực tiếp vào trạng thái chia sẻ
class GameWorld:
position = {} # trạng thái chia sẻ có thể thay đổi
velocity = {} # trạng thái chia sẻ có thể thay đổi
def physics_tick(world):
for entity in world.entities:
world.position[entity] += world.velocity[entity] # ghi trạng thái chia sẻ giữa vòng lặp
# SAU: snapshot được đóng băng trước pha; các ghi sẽ đi vào bộ đệm next_state
def physics_tick(world):
snapshot = world.freeze() # immutable view
next_state = {}
for entity in snapshot.entities:
next_state[entity] = snapshot.position[entity] + snapshot.velocity[entity]
world.merge(next_state) # atomic merge at phase boundary
Mỗi hệ thống con đều đọc snapshot. Không hệ thống con nào ghi vào snapshot. Các thao tác ghi được tích lũy trong một bộ đệm và được hợp nhất nguyên tử tại ranh giới pha. Các hệ thống con giờ đây thực thi độc lập: không tranh chấp khóa, không phụ thuộc thứ tự, không liên kết ẩn.
Áp dụng bản sửa lỗi
Một đội báo cáo lỗi: hệ thống animation và hệ thống collision của engine trò chơi đều ghi vào cùng một đối tượng transform của thực thể. Khi cả hai chạy trong cùng một tick, kết quả collision phụ thuộc vào việc animation có chạy trước hay không. Việc thêm mutex đã sửa thứ tự, nhưng giờ animation bị treo mỗi khi collision thực hiện broad-phase sweep.