2015-12-04 23 views
13

Tôi có bản đồ với các đối tượng cần được giải phóng trước khi xóa bản đồ. Tôi bị cám dỗ để lặp lại trên bản đồ và loại bỏ/giải phóng các đối tượng khi tôi đi qua nó.Truy cập bản đồ đồng thời Golang với phạm vi

Đây là một mock up dụ https://play.golang.org/p/kAtPoUgMsq

Kể từ khi cách duy nhất để lặp bản đồ là thông qua phạm vi, làm thế nào tôi sẽ đồng bộ hóa nhiều nhà sản xuất và nhiều người tiêu dùng?

Tôi không muốn đọc khóa bản đồ vì điều đó sẽ làm cho các phím xóa/sửa đổi trong khi lặp lại không thể.

+0

Chúng tôi cần thêm ngữ cảnh để làm việc với điều này. Bản đồ chứa đựng những gì? Nó to lớn? Làm thế nào nhanh chóng được phát hành một điều? (Cái gì _is_ phát hành?) Có phải là một thảm họa nếu một đối tượng được phát hành được sử dụng bởi một goroutine khác, và nếu như vậy, điều gì quyết định một đối tượng được chọn ra khỏi bản đồ được sử dụng trong bao lâu? Ứng dụng là gì và ưu tiên của nó (ví dụ: tối đa hóa thông lượng so với giới hạn thời gian chờ) là gì? – twotwotwo

Trả lời

4

Bạn không nêu tất cả các yêu cầu (ví dụ có thể việc phát hành của nhiều đối tượng xảy ra cùng một lúc, vv), nhưng giải pháp đơn giản nhất tôi có thể nghĩ là để loại bỏ các yếu tố và khởi động một goroutine phát hành cho mỗi người trong số các yếu tố loại bỏ:

for key := range keysToRemove { 
    if v, ok := m[k]; ok { 
     delete(m, k) 
     go release(k, v) 
    } 
} 
+0

Phương pháp được đưa ra trong câu trả lời này có thực sự đủ không? (Esp. Sau 1.6 thay đổi?) Có một vị trí trong đặc tả ngôn ngữ mà tại đó điều này được xóa/trả lời dứt khoát không? – BadZen

+0

Trong mẫu mã phía trên bản đồ được truy cập từ một goroutine duy nhất, do đó không cần đồng bộ hóa vì không có quyền truy cập đồng thời. – kostya

+0

Tất nhiên OP là giả sử sẽ có các nhà văn đồng thời trong quá trình lặp lại. Ông nói: "Tôi không muốn đọc khóa bản đồ vì điều đó sẽ làm cho các phím xóa/sửa đổi trong quá trình lặp lại không thể." Chỉ vì anh ta không/hiển thị/các nhà văn không có nghĩa là họ không tham gia. – BadZen

2

cập nhật tháng 8 năm 2017 (golang 1.9)

Bây giờ bạn có một Map loại mới trong gói sync là một bản đồ đồng thời với vô khấu hao-liên tục theo thời gian, các cửa hàng, và xóa dần.
Đồng thời, nhiều goroutine cũng an toàn để gọi đồng thời các phương thức của Map.


Original câu trả lời Tháng Mười Một 2016

Tôi không muốn đọc khóa bản đồ

Điều đó làm cho ý nghĩa, vì một xóa khỏi bản đồ được coi là một hoạt động viết, và phải được tuần tự hóa với tất cả các lần đọc và viết khác. Điều đó ngụ ý một khóa ghi để hoàn thành việc xóa. (Nguồn: this answer)

Giả sử trường hợp xấu nhất (nhiều tác giả và độc giả), bạn có thể có một cái nhìn tại thi hành orcaman/concurrent-map, trong đó có một Remove() method sử dụng nhiều sync.RWMutex vì, để tránh tắc nghẽn khóa, bản đồ này đồng thời là dived đến một số (SHARD_COUNT) bản đồ mảnh.
Điều này nhanh hơn chỉ sử dụng một RWMutexas in this example.

6

Có rất nhiều cách để bạn có thể dọn dẹp mọi thứ từ map mà không cần truy cập bản đồ. Những gì làm việc cho ứng dụng của bạn phụ thuộc rất nhiều vào những gì nó đang làm.

0) Chỉ cần khóa bản đồ trong khi bạn làm việc trên đó. Nếu bản đồ không quá lớn, hoặc bạn có dung sai trễ, nó sẽ hoàn thành công việc một cách nhanh chóng (về thời gian bạn chi tiêu cho nó) và bạn có thể tiếp tục suy nghĩ về những thứ khác. Nếu nó trở thành một vấn đề sau này, bạn có thể quay trở lại vấn đề sau đó.

1) Sao chép các đối tượng hoặc con trỏ ra và xóa bản đồ trong khi giữ khóa, sau đó nhả các đối tượng trong nền. Nếu vấn đề là sự chậm phát hành bản thân sẽ giữ cho khóa được giữ trong một thời gian dài, đây là giải pháp đơn giản cho điều đó.

2) Nếu đọc hiệu quả về cơ bản là quan trọng, hãy sử dụng atomic.Value. Điều đó cho phép bạn thay thế hoàn toàn một bản đồ bằng một bản đồ mới và khác.Nếu viết về cơ bản là 0% khối lượng công việc của bạn, thì hiệu quả đọc sẽ cân bằng chi phí tạo bản đồ mới trên mọi thay đổi. Điều đó hiếm, nhưng điều đó xảy ra, ví dụ: encoding/gob có bản đồ toàn cầu về các loại được quản lý theo cách này.

3) Nếu không ai trong số đó làm mọi thứ bạn cần, hãy tinh chỉnh cách bạn lưu trữ dữ liệu (ví dụ: phân phát bản đồ). Thay thế bản đồ của bạn bằng 16 bản đồ và các khóa băm để quyết định bản đồ nào thuộc về, và sau đó bạn có thể khóa từng mảnh một, để dọn dẹp hoặc viết khác.

Ngoài ra còn có vấn đề của một cuộc đua giữa phát hành và sử dụng: goroutine A nhận được một cái gì đó từ bản đồ, B xóa bản đồ và phát hành điều, A sử dụng điều phát hành.

Một chiến lược có để khóa từng giá trị trong khi bạn sử dụng hoặc giải phóng nó; thì bạn cần khóa nhưng không cần khóa.

Cách khác là chịu đựng hậu quả của chủng tộc nếu chúng được biết đến và không phải là thảm họa; ví dụ: quyền truy cập đồng thời vào các tài liệu của nó được cho phép một cách rõ ràng, do đó việc đóng kết nối đang sử dụng có thể khiến yêu cầu lỗi nhưng không dẫn đến hành vi ứng dụng chưa xác định. Bạn phải thực sự chắc chắn rằng bạn biết những gì bạn đang nhận được vào sau đó, mặc dù, vì many benign-seeming races aren't.

Cuối cùng, có thể ứng dụng của bạn đã đảm bảo không có đối tượng đang sử dụng nào được giải phóng, ví dụ: có một số tham chiếu được duy trì một cách an toàn trên các đối tượng và chỉ các đối tượng không sử dụng được giải phóng. Sau đó, tất nhiên, bạn không phải lo lắng.

Có thể sẽ cố gắng thay thế các khóa này bằng các kênh bằng cách nào đó nhưng tôi không thấy bất kỳ lợi ích nào từ nó. Đó là đẹp khi bạn có thể thiết kế ứng dụng của mình suy nghĩ chủ yếu về mặt giao tiếp giữa các quy trình thay vì dữ liệu được chia sẻ, nhưng khi bạn có dữ liệu được chia sẻ, không sử dụng trong giả vờ khác. Việc loại trừ quyền truy cập không an toàn vào dữ liệu được chia sẻ là những khóa được sử dụng.

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