2014-05-14 21 views
5

Hãy nói rằng tôi có một danh sách các số nguyên trong hệ thống:F # đồng bộ truy cập vào danh sách

let mutable data: int list = [1; 2; 3; 4; 5] 

được cập nhật (bằng cách thêm một yếu tố) bằng cách tương đối vài người sản xuất và tiêu thụ bởi nhiều của người tiêu dùng .

Lưu ý: không sao nếu người tiêu dùng nhận được dữ liệu hơi lỗi thời.

Điều gì sẽ là cách thích hợp để đồng bộ hóa quyền truy cập vào biến này?

A) Cách tiếp cận an toàn sẽ là đưa biến này vào đại lý và truy cập thông qua tin nhắn được tuần tự, chúng tôi thậm chí không cần sửa đổi mutable tại đây. Nhưng cách tiếp cận này có vẻ là phụ tối ưu, bởi vì nó sẽ không cần thiết làm cho tất cả các truy cập đọc được đồng bộ hóa.

B phân công tham khảo) AFAIK là nguyên tử trong .NET, vì vậy giữa một nhà xuất bản và tất cả người tiêu dùng một nhiệm vụ đơn giản là đủ:

Nhà xuất bản: data <- newItem :: data

Tiêu Dùng: data |> process

Vì vậy, chỉ khóa đơn giản giữa các nhà xuất bản sẽ đủ để kết thúc luồng công việc này?

let monitor = object() 

Nhà xuất bản: lock monitor (fun() -> data <- newItem::data)

Am I đúng với giả định của tôi? Cách tiếp cận nào được ưa thích và sẽ thành ngữ hơn đối với F #? Bất kỳ lựa chọn tốt hơn?

+0

ý tưởng khác là lùi lại một bước và suy nghĩ về thông điệp đi qua, chứ không phải là bộ nhớ chia sẻ, như vậy tránh được sự cần thiết của ổ khóa. Ví dụ.: Http://blogs.msdn.com/b/dsyme/archive/2010/02/15/async-and-parallel-design-patterns-in-f-part-3-agents.aspx – Mau

+0

Đó là tùy chọn 'A' được liệt kê trong câu hỏi, nó không có vẻ rất hiệu quả cho trường hợp sử dụng này. – Grozz

Trả lời

8

Bạn có thể sử dụng để xử lý Interlocked.CompareExchange xuất bản mà không cần khóa một cách rõ ràng:

let mutable data = [1;2;3;4;5] 

let newValue = 0 

// To publish: 
let mutable tmp = data; 
while not(tmp.Equals(Interlocked.CompareExchange(&data, newValue::data, tmp))) do 
    tmp <- data 

này có khả năng sẽ cung cấp một lợi ích nhỏ nếu bạn đã đồng bộ nhà văn.

Nếu bạn quyết định bạn muốn người tiêu dùng luôn có dữ liệu mới nhất, ReaderWriterLockSlim sẽ cho phép bạn đồng bộ hóa hoàn toàn dữ liệu mà không buộc phải đọc để chặn trên mỗi cuộc gọi.

Điều đó có thể giống như thế:

let mutable data = [1;2;3;4;5] 
let rwl = ReaderWriterLockSlim() 

let newValue = 0 

// To publish: 
let publish newValue = 
    rwl.EnterWriteLock() 
    try 
     data <- newValue :: data 
    finally 
     rwl.ExitWriteLock() 

// To read: 
let readCurrent = 
    rwl.EnterReadLock() 
    try 
     data 
    finally 
     rwl.ExitReadLock() 
0

Nếu dữ liệu chia sẻ của bạn là không thay đổi, bạn có thể làm điều này một cách an toàn:

let monitor = new System.Object() 
let data : int list ref = ref List.empty 

let modData (modFun : int list -> int list) = 
    lock (monitor) (fun _ -> data := modFun !data) 

Bạn có thể đọc dữ liệu khi đã bao giờ bạn thích mà không cần khóa. Dữ liệu là không thay đổi nên không thể "giữa các trạng thái". Nếu bạn cần đọc và viết nguyên tử, bạn có thể làm điều đó trong "modFun".

Cách sử dụng Ví dụ:

modData (function |(head::tail) -> tail |_ -> List.Empty) //Remove one 
modData (fun thelist -> 1::thelist) //Add number 1 to head 
Các vấn đề liên quan