Đếm đồng thời là khó. Giả sử số đếm là 0. Nếu hai người dùng đều nhấn điểm cuối tại khoảng thời gian đủ gần, họ có thể nhận được giá trị 0, tăng giá trị đó lên 1 và đặt lại. Hai người dùng nhấn điểm cuối, nhưng số kết quả là 1, không phải 2. Để giải quyết vấn đề này, bạn cần sử dụng một kho lưu trữ dữ liệu hỗ trợ gia tăng nguyên tử (như trong một thao tác mà chỉ một tiến trình có thể thực hiện tại một thời điểm).
Bạn không thể sử dụng một Python đơn giản global
vì các máy chủ WSGI sẽ sinh ra nhiều quy trình, do đó, mỗi người sẽ có bản sao độc lập riêng của họ trên toàn cầu. Các yêu cầu lặp lại có thể được xử lý bởi các quá trình khác nhau, dẫn đến các giá trị khác nhau, không đồng bộ.
Giải pháp đơn giản nhất là Python multiprocessing.Value
. Điều này đồng bộ hóa quyền truy cập vào một giá trị được chia sẻ trên các quy trình, miễn là các quy trình được sinh ra sau khi giá trị được tạo.
from flask import Flask, jsonify
from multiprocessing import Value
counter = Value('i', 0)
app = Flask(__name__)
@app.route('/')
def index():
with counter.get_lock():
counter.value += 1
return jsonify(count=counter.value)
app.run(processes=8)
# access http://localhost:5000/ multiple times quickly, the count will be correct
vẫn còn một số hãy cẩn thận:
- Các dữ liệu chỉ kéo dài chừng nào người quản lý là còn sống. Nếu bạn khởi động lại máy chủ, bộ đếm sẽ đặt lại.
- Nếu các quy trình ứng dụng được phân phối trên nhiều máy, bộ nhớ dùng chung gặp vấn đề tương tự như hình cầu: chúng chỉ được đồng bộ hóa trên máy cục bộ, không phải trên mạng.
Đối với các tình huống thực tế, Redis là giải pháp mạnh mẽ hơn nhiều. Máy chủ độc lập với ứng dụng web, có các tùy chọn cho sự kiên trì và có thể làm tăng số nguyên tử. Nó cũng có thể được sử dụng cho các phần khác của ứng dụng, chẳng hạn như bộ nhớ đệm.