2014-05-09 16 views
7

Tôi đang cố gắng sử dụng các giao dịch Django 1.6 để tránh điều kiện chạy đua trên một trò chơi mà tôi đang phát triển. Máy chủ trò chơi có một mục tiêu đơn giản: để ghép nối hai người chơi.Giao dịch Django 1.6 để tránh điều kiện đua xe

cách tiếp cận hiện tại của tôi là:

  1. Người dùng muốn chơi
  2. sẽ kiểm tra máy chủ nếu có bất cứ ai khác chờ đợi để chơi.
    1. Nếu có không, nó tạo ra một đối tượng GameConnection (mà có một định danh duy nhất - uuid4).
    2. Nếu có , số nhận dạng GameConnection và xóa GameConnection.

Đây là mã:

# data['nickname'] = user's choice 
games = GameConnection.objects.all() 
if not games: 
    game = GameConnection.objects.create(connection=unicode(uuid.uuid4())) 
    game.nick1 = data["nickname"] 
    game.save() 

    response = HttpResponse(json.dumps({'connectionId': game.connection, 'whoAmI': 1, 'nick1': game.nick1, 'nick2': ""})) 
else: 
    game = games[0] 
    conn = game.connection 
    nick1 = game.nick1 
    nick2 = data["nickname"] 
    game.delete() 
    response = HttpResponse(json.dumps({'connectionId': conn, 'whoAmI': 2, 'nick1': nick1, 'nick2': nick2})) 

return response 

Rõ ràng có một điều kiện chủng tộc trên các mã trên. Vì mã này không phải là nguyên tử, có thể xảy ra rằng:

  • Kiểm tra kết nối trò chơi. Không tìm thấy.
  • A tạo kết nối trò chơi.
  • B kiểm tra kết nối trò chơi. Tìm một (A).
  • C kiểm tra kết nối trò chơi. Tìm một (A).
  • B nhận mã nhận dạng kết nối của A và bắt đầu trò chơi.
  • C nhận mã nhận dạng kết nối của A và bắt đầu trò chơi.

Tôi đã cố gắng thực hiện nhưng toàn bộ khối này dưới with transaction.atomic(): hoặc sử dụng trang trí @transaction.atomic. Nhưng vẫn còn, tôi có thể tái tạo điều kiện chủng tộc.

Tôi chắc chắn có điều gì đó về động lực giao dịch mà tôi thiếu ở đây. Ai có thể làm sáng tỏ không?

+0

Tôi không phải là chuyên gia, nhưng theo sự hiểu biết của tôi, các giao dịch nguyên tử được áp dụng để ghi. Trong trường hợp của bạn, bạn có thể muốn sử dụng một số loại khóa mutex để đảm bảo chỉ có một cặp xảy ra tại một thời điểm. Điều này tương tự như @synchronized trong Java. Không hiệu quả ở tất cả các hiệu suất khôn ngoan mặc dù. –

Trả lời

2

@Sai đang đi đúng hướng ... điều quan trọng là khóa/mutex sẽ không xảy ra cho đến khi viết (hoặc xóa). Khi được mã hóa, sẽ luôn có một khoảng thời gian giữa "khám phá" (đọc) của kết nối đang chờ xử lý và "yêu cầu" (ghi/khóa) của kết nối đang chờ xử lý, không có cách nào để biết rằng kết nối đang trong quá trình được xác nhận quyền sở hữu.

Nếu bạn đang sử dụng PostgreSQL (khá chắc chắn MySQL hỗ trợ nó, quá), bạn có thể buộc các khóa với "chọn để cập nhật", mà sẽ ngăn chặn một yêu cầu khác từ nhận cùng hàng đến khi giao dịch hoàn thành:

game = GameConnection.objects.all()[:1].select_for_update() 
if game: 
    #do something, update, delete, etc. 
else: 
    #create 

Lưu ý cuối cùng - hãy xem xét điều gì đó khác với số all() để biết rõ về trò chơi nào có thể được chọn (ví dụ: đặt hàng bằng dấu thời gian "được tạo" hoặc thứ gì đó). Hy vọng rằng sẽ giúp.

Các vấn đề liên quan