Tôi đang làm việc trên ứng dụng mạng haskell và tôi sử dụng mẫu diễn viên để quản lý đa luồng. Một điều tôi gặp phải là làm thế nào để lưu trữ ví dụ một tập hợp các ổ cắm/tay cầm của khách hàng. Tất nhiên là phải có thể truy cập cho tất cả các chủ đề và có thể thay đổi khi khách hàng đăng nhập/tắt.Haskell - Biến thể dựa trên diễn viên
Vì tôi là đến từ thế giới bắt buộc Tôi nghĩ về một số loại khóa cơ chế nhưng khi tôi nhận thấy như thế nào xấu xí này là tôi nghĩ về mutability "tinh khiết", cũng thực sự nó là loại tinh khiết:
import Control.Concurrent
import Control.Monad
import Network
import System.IO
import Data.List
import Data.Maybe
import System.Environment
import Control.Exception
newStorage :: (Eq a, Show a) => IO (Chan (String, Maybe (Chan [a]), Maybe a))
newStorage = do
q <- newChan
forkIO $ storage [] q
return q
newHandleStorage :: IO (Chan (String, Maybe (Chan [Handle]), Maybe Handle))
newHandleStorage = newStorage
storage :: (Eq a, Show a) => [a] -> Chan (String, Maybe (Chan [a]), Maybe a) -> IO()
storage s q = do
let loop = (`storage` q)
(req, reply, d) <- readChan q
print ("processing " ++ show(d))
case req of
"add" -> loop ((fromJust d) : s)
"remove" -> loop (delete (fromJust d) s)
"get" -> do
writeChan (fromJust reply) s
loop s
store s d = writeChan s ("add", Nothing, Just d)
unstore s d = writeChan s ("remove", Nothing, Just d)
request s = do
chan <- newChan
writeChan s ("get", Just chan, Nothing)
readChan chan
Vấn đề là một chủ đề (diễn viên) đang quản lý danh sách các mục và sửa đổi danh sách theo yêu cầu gửi đến. Kể từ khi thread thực sự rẻ tôi nghĩ rằng đây có thể là một thay thế chức năng thực sự tốt đẹp.
Tất nhiên đây chỉ là một mẫu thử nghiệm (một bằng chứng bẩn nhanh về khái niệm). Vì vậy, câu hỏi của tôi là:
- Đây có phải là cách "tốt" để quản lý các biến có thể thay đổi được chia sẻ (trong thế giới diễn viên) không?
- Đã có thư viện cho mẫu này chưa? (Tôi đã tìm kiếm nhưng tôi thấy không có gì)
Kính trọng, Chris
Nếu bạn sẵn sàng khám phá các lựa chọn thay thế cho mô hình diễn viên, tôi khuyên bạn nên dùng thử [Software Transactional Memory] của Haskell (https://en.wikipedia.org/wiki/Software_transactional_memory). Đó là một cơ chế tuyệt đẹp tương tự như các giao dịch cơ sở dữ liệu. Xem [Chương 28] (http://book.realworldhaskell.org/read/software-transactional-memory.html) trong The Real World Haskell. –
Về mặt kỹ thuật là một lựa chọn tuyệt vời nhưng tôi nghe nói rằng sử dụng STM với một số lượng lớn các chủ đề (một luồng cho mỗi khách hàng là tiêu chuẩn trong haskell) và các hoạt động tương đối dài (xóa một mục khỏi danh sách là O (n), tất nhiên là bộ băm/bản đồ có thể giúp đỡ ở đây) có thể làm giảm hiệu suất của STM bằng một số lượng lớn. Và tất nhiên kênh MVar có thể được thay thế bằng kênh STM có nghĩa là sử dụng tốt nhất của hai kỹ thuật. EDIT: Các mẫu diễn viên nói chung là thực sự tốt đẹp trong tình huống như vậy, bởi vì xóa/thêm một mục là O (1) (chỉ cần gửi một tin nhắn) Công việc thực tế được thực hiện trong một chủ đề ... – Kr0e
Bạn nói đúng. Với STM nó có thể xảy ra rằng các giao dịch được khởi động lại nhiều lần, dẫn đến hiệu suất giảm. Nhưng nếu các hoạt động đồng bộ của bạn mất nhiều thời gian, bạn cũng có thể gặp các vấn đề tương tự với các diễn viên - nếu có nhiều thông điệp hơn nó có thể xử lý, trạng thái của nó sẽ tụt lại phía sau thực tế. Vì vậy, việc sử dụng các cây cân bằng ('Map' /' Set') hoặc các bộ băm dựa trên 'ST/IO' chắc chắn sẽ giúp ích. –