2012-04-11 29 views
7

Tôi đang xem xét sử dụng TVar để lưu trữ một số trạng thái trong ứng dụng web (có thể được tạo lại khi khởi động lại). Tuy nhiên, các khía cạnh tranh chấp của TVar liên quan đến tôi. Dường như một giao dịch ngắn hạn thường xuyên có thể khiến các giao dịch dài hơn bị gián đoạn bằng cách liên tục làm gián đoạn chúng. Ngoài ra, khi các giao dịch chạy lâu hơn tiếp tục khởi động lại, điều này sẽ làm tăng tải trên CPU, có xu hướng tăng thêm độ dài của các giao dịch này. Cuối cùng tôi cảm thấy điều này có thể khiến máy chủ trở nên hoàn toàn không phản hồi.Haskell: TVar: Ngăn chặn nạn đói

Xét này, tôi có những câu hỏi này:

(1) TVar (hoặc kiểu dữ liệu khác) có thể sử dụng ổ khóa, không đồng thời nỗ lực/lần thử lại.

(2) TVar (hoặc loại dữ liệu khác) có một số cơ chế tranh chấp khác nhau, nghĩa là "cho phép giao dịch chạy một giây trước khi chạy giao dịch khác", hoặc ít nhất một số đảm bảo rằng giao dịch cuối cùng sẽ hoàn thành. ngăn chặn starvation cho các giao dịch đang chạy lâu hơn).

+2

Lưu ý 'thử lại 'không khởi động lại giao dịch ngay lập tức; các giao dịch chỉ thử lại khi 'TVar' chúng sử dụng được sửa đổi. – ehird

+0

@ehird: Các giao dịch không tự động thử lại ngay lập tức nếu một giao dịch khác ghi vào TV mà chúng đã đọc trước đó (ngay cả khi không có lệnh gọi lại 'thử lại ')? – Clinton

+0

@Clinton: Có, họ thử lại, nhưng chỉ sau khi hệ thống thời gian chạy phát hiện khả năng có kết quả khác nhau của giao dịch. I E. nó chờ cho đến khi một TV đọc trước khi thử lại đã thay đổi. Mà biến bận rộn chờ đợi vào một chương trình thông báo đẩy. – jmg

Trả lời

3

Đây chỉ là mối quan tâm nếu bạn có nhiều giao dịch rẻ tiền cập nhật dữ liệu và một số giao dịch rẻ tiền đọc dữ liệu đó. Analytics có thể là một tập dữ liệu được cập nhật trực tiếp.

Nếu bạn thực sự lo lắng về điều này, hãy cân nhắc sử dụng TV cờ. Đặt nó thành false và kiểm tra xem nó có sai ở đầu mỗi giao dịch giá rẻ hay không, gọi số retry nếu không. Sau đó, chỉ cần đặt nó thành true trước khi tham gia vào giao dịch dài hạn của bạn và đặt nó thành false khi thoát. Cách khác, bạn chỉ cần bảo vệ trạng thái của mình sau một số TMVar.Tính toán longrunning của bạn mất tmvar nguyên tử, làm những gì nó cảm thấy như thế, và sau đó trả về nó. Các giao dịch khác diễn ra hoàn toàn trong một giao dịch STM thực tế duy nhất.

Hãy nhớ rằng, một giao dịch STM chạy dài là một loại quái vật phức tạp. Do lười biếng, bạn có thể đặt một giá trị đắt tiền vào một var rẻ. Bạn cũng có thể đọc một "ảnh chụp nhanh" dữ liệu từ một loạt các vars rất nhanh chóng. Để có giao dịch thực sự dài, bạn cần phải đọc từ một loạt các vars, sau đó dựa trên những gì bạn đã đọc, tính những gì vars bạn sẽ viết giá trị mới vào (hoặc đọc các giá trị từ), và tính toán chính nó phải tốn kém. Vì vậy, có khả năng bạn thậm chí không trong kịch bản đó để bắt đầu với!

5

Tôi không nghĩ rằng có một cách để đảm bảo tự do đói, trừ khi bạn thay đổi mã thời gian chạy của chính hệ thống STM. Theo ý kiến ​​của tôi, đưa vào ổ khóa để tránh tranh chấp trong số TVars đánh bại mục đích của việc có STM ở nơi đầu tiên, kể từ khi toàn bộ điểm sử dụng STM là để thoát khỏi cách tiếp cận dựa trên khóa dễ bị lỗi cổ điển để lập trình đồng thời.

Chắc chắn, đói có thể gây mất hiệu suất đáng kể, nhưng chỉ với giả định rằng các giao dịch lớn như vậy thực tế là cần thiết. Một nguyên tắc thiết kế mà tôi cố gắng ghi nhớ, là sử dụng TVars ở mức độ chi tiết thấp. Ví dụ: thay vì đặt toàn bộ Data.Map vào TVar, điều này có thể gây tranh cãi mỗi lần một mục được cập nhật, bạn có thể sử dụng cấu trúc dữ liệu thân thiện với STM hơn, như skiplists [1].

[1] http://hackage.haskell.org/package/tskiplist

+0

Tôi không thực sự hiểu cách STM ít bị lỗi. Không thường xuyên các giao dịch chạy ngắn có hiệu quả đặt một khóa không bao giờ được phát hành cho các giao dịch đang chạy lâu hơn? Không phải là nhiều hơn dễ bị lỗi như dưới một hệ thống dựa trên khóa, ít nhất tại một số điểm giao dịch chạy lâu hơn sẽ lấy khóa và hoàn thành? STM dường như buộc các lập trình viên phải đảm bảo rằng giao dịch chạy dài nhất của họ mất ít thời gian hơn để hoàn thành hơn khoảng cách dài nhất giữa các giao dịch. Có lẽ tôi đang thiếu một cái gì đó ở đây mặc dù. – Clinton

+0

Nếu tôi hiểu chính xác, trong hệ thống khóa, nếu giao dịch hiện đang diễn ra, một giao dịch khác cần chờ. Theo STM, nếu một giao dịch hiện đang được tiến hành, thay vào đó nó bắt đầu hoạt động thì cuối cùng nó sẽ bị xóa. Trong cả hai trường hợp không có công việc hữu ích được thực hiện, vì vậy tôi không thấy làm thế nào STM là ít "khóa" hơn so với ổ khóa thông thường. Nhưng một lần nữa, có lẽ tôi đang thiếu một cái gì đó. – Clinton

+0

@Clinton: Vấn đề chính với ổ khóa không phải là đói, nhưng ít khóa hoặc deadlocks. Vì vậy, vấn đề với ổ khóa thường là sự chính xác không phải vấn đề hiệu suất. Trong khi các vấn đề với STM có thể là vấn đề hiệu suất. Bạn cũng nên xem xét khả năng lười biếng. Laziness làm cho nó có thể viết kết quả của một tính toán thuần túy dài chạy trong một giao dịch ngắn chạy vào một TVar. – jmg

0

này được viết dưới dạng một comment để một trong những ý kiến ​​của bà Clinton về Peters câu trả lời. Nhưng nó đã trở thành dài.

Hãy xem xét, bạn có hai tài khoản ngân hàng: A và B. Mỗi tài khoản được bảo vệ bằng khóa riêng. Bây giờ, bạn có hai giao dịch đầu tiên chuyển tiền từ A đến B, và lần thứ hai từ B đến A. Mỗi lần đầu tiên lấy khóa của tài khoản nguồn và sau đó của tài khoản đích, chuyển tiền và giải phóng khóa. Nếu bạn không may mắn hai giao dịch sẽ chạy vào một khóa chết, và sẽ không có gì được thực hiện với hai tài khoản đó. Nếu bạn làm điều đó trong STM, chúng sẽ chạy theo nhau. Nếu bạn có vô hạn nhiều loại đầu tiên, họ có thể bỏ đói giao dịch thứ hai. Nhưng bạn vẫn nhận được rất nhiều. Trong khi với khóa không có gì xảy ra.

STM đảm bảo rằng không có cuộc đua dữ liệu nào có TV! Không có gì như vậy. Với khóa, bạn có thể đến kết luận đó sau khi kiểm tra rất cẩn thận mã của bạn. Và mọi dòng bạn thêm có thể làm mất hiệu lực kết luận của bạn hoàn toàn.