2016-04-03 21 views
8

Tôi tự hỏi giải thích rõ ràng nhất cho câu nói nổi tiếng này là gì:Giải thích: Không giao tiếp bằng cách chia sẻ bộ nhớ; chia sẻ bộ nhớ bằng cách liên lạc

Không giao tiếp bằng cách chia sẻ bộ nhớ; chia sẻ bộ nhớ bằng cách giao tiếp. (R. Pike)

Trong The Go Memory Model tôi có thể đọc:

Một gửi trên một kênh xảy ra trước khi tương ứng nhận được từ kênh đó hoàn tất. (Golang Spec)

Ngoài ra còn có một số golang article dành riêng giải thích báo giá. Và đóng góp chính là working example cũng bởi Andrew G.

Vâng. Đôi khi quá nhiều nói chuyện xung quanh .... Tôi có nguồn gốc từ các báo giá Spec Memory và cũng bằng cách nhìn vào ví dụ làm việc này:

Sau khi goroutine1 gửi (bất cứ điều gì) đến một goroutine2 thông qua một kênh, sau đó tất cả thay đổi (bất cứ nơi nào trong bộ nhớ) được thực hiện bởi goroutine1 phải được hiển thị cho goroutine2 sau khi nó nhận được thông qua cùng một kênh. (Golang Bổ đề bởi Me :)

therfore tôi lấy được Down để giải thích đất của câu nói nổi tiếng:

Để đồng bộ hóa truy cập bộ nhớ giữa hai goroutines, bạn không cần phải gửi bộ nhớ mà qua kênh. Đủ tốt là nhận được từ kênh (thậm chí không có gì). Bạn sẽ thấy bất kỳ thay đổi nào được viết (ở bất kỳ đâu) bằng cách gửi goroutine (tới kênh) tại thời điểm gửi. (Tất nhiên, giả sử không có goroutines khác đang viết với cùng bộ nhớ.) Update (2) 8-26-2017

Tôi thực sự có hai câu hỏi:

1) là kết luận của tôi đúng ?

2) Lời giải thích của tôi có giúp ích không?

Cập nhật (1) Tôi giả định kênh unbuffered. Cho phép hạn chế bản thân để đầu tiên để tránh đại tu chính mình với quá nhiều ẩn số. Xin vui lòng, chúng ta cũng tập trung vào việc sử dụng đơn giản hai goroutines giao tiếp qua một kênh đơn và các hiệu ứng bộ nhớ liên quan chứ không phải trên các thực tiễn tốt nhất - vượt quá phạm vi của câu hỏi này.

Để hiểu rõ hơn phạm vi câu hỏi của tôi giả định rằng goroutines có thể truy cập bất kỳ cấu trúc bộ nhớ nào - không chỉ là cấu trúc bộ nhớ - và nó có thể là cấu trúc lớn, nó có thể là chuỗi, bản đồ, mảng, bất cứ thứ gì.

+0

Kiểm tra viết TODO – honzajde

Trả lời

2

Thực chất là có. Bất kỳ giá trị nào được gán cho các biến trước khi gửi kênh đều đủ điều kiện để được quan sát sau khi kênh được đọc, do hoạt động kênh áp đặt ràng buộc đặt hàng. Nhưng điều quan trọng cần nhớ là phần còn lại của phương trình: nếu bạn muốn bảo đảm rằng các giá trị đó được quan sát, bạn phải đảm bảo rằng không ai khác có thể ghi vào các biến đó giữa ghi và đọc. Rõ ràng bằng cách sử dụng khóa sẽ có thể, nhưng vô nghĩa cùng một lúc bởi vì nếu bạn đã kết hợp ổ khóa và sửa đổi bộ nhớ chéo chủ đề, những lợi ích mà bạn nhận được từ các kênh?Bạn có thể truyền xung quanh một cái gì đó đơn giản như boolean, như một mã thông báo cho phép truy cập độc quyền vào dữ liệu toàn cục, và nó sẽ chính xác 100% về bảo đảm mô hình bộ nhớ (miễn là mã của bạn không có lỗi), nó chỉ có thể là một thiết kế xấu bởi vì bạn sẽ làm mọi thứ ẩn chứa và hành động-ở-một-khoảng-y mà không có lý do chính đáng; truyền dữ liệu một cách rõ ràng thường sẽ rõ ràng hơn và ít bị lỗi hơn.

+0

Cho đến nay, điều này giải quyết hầu hết vấn đề của câu hỏi của tôi. Cám ơn. Vẫn đang chờ Rob P. nói phần của mình mặc dù :) – honzajde

3

Tôi không nghĩ vậy. Gist thay vì bảo vệ một địa chỉ bộ nhớ cố định bằng một khóa hoặc các nguyên thủy đồng thời khác, bạn có thể kiến ​​trúc chương trình theo cách chỉ có một luồng thực thi được phép truy cập bộ nhớ này theo thiết kế.

Cách dễ dàng để đạt được điều này là chia sẻ tham chiếu tới bộ nhớ theo kênh. Khi bạn gửi tham chiếu qua kênh, bạn hãy quên nó. Bằng cách này chỉ có thói quen sẽ tiêu thụ kênh đó sẽ có quyền truy cập vào nó.

+0

Có, ý chính là về một cái gì đó hoàn toàn khác - như bạn mô tả trong đoạn thứ hai của bạn. Nhưng nếu tôi sai thì tôi sai ở đâu ?. – honzajde

10

Trích dẫn nổi tiếng này có thể hơi khó hiểu nếu được chụp quá nhiều. Hãy phá vỡ nó xuống thành phần cơ bản hơn của nó, và định nghĩa chúng đúng cách:

Don't communicate by sharing memory; share memory by communicating 
     ---- 1 ---- ------ 2 ----- ---- 3 ----- ----- 4 ----- 
  1. Điều này có nghĩa rằng chủ đề khác nhau thực hiện sẽ được thông báo về sự thay đổi của nhà nước của đề khác bằng cách đọc bộ nhớ đó sẽ được sửa đổi ở đâu đó khác. Một ví dụ hoàn hảo về điều này (mặc dù cho các quy trình thay vì chủ đề) là API bộ nhớ chia sẻ POSIX: http://man7.org/linux/man-pages/man7/shm_overview.7.html. Kỹ thuật này cần đồng bộ hóa thích hợp vì các cuộc đua dữ liệu có thể xảy ra khá dễ dàng.
  2. Ở đây điều này có nghĩa rằng thực sự có một phần bộ nhớ, vật lý hoặc ảo, có thể được sửa đổi từ một số chủ đề và đọc từ những chủ đề đó. Không có khái niệm quyền sở hữu rõ ràng, không gian bộ nhớ có thể truy cập như nhau từ tất cả các chủ đề.
  3. Điều này hoàn toàn khác. Trong Go, chia sẻ bộ nhớ giống như ở trên là có thể, và dữ liệu có thể xảy ra khá dễ dàng, vậy điều này thực sự có nghĩa là sửa đổi biến trong goroutine, có thể là một giá trị đơn giản như một cấu trúc dữ liệu phức tạp như bản đồ, và cho đi quyền sở hữu bằng cách gửi giá trị hoặc con trỏ tới giá trị đến một goroutine khác thông qua cơ chế kênh. Vì vậy, lý tưởng, không có không gian dùng chung, mỗi goroutine chỉ thấy phần bộ nhớ mà nó sở hữu.
  4. Giao tiếp ở đây đơn giản có nghĩa là một kênh, chỉ là một hàng đợi, cho phép một goroutine đọc từ nó và được thông báo về quyền sở hữu một phần bộ nhớ mới, trong khi một số khác gửi và chấp nhận mất quyền sở hữu. Nó là một mẫu truyền thông điệp đơn giản.

Tóm lại, những gì các phương tiện trích dẫn có thể được tóm tắt như thế này:

Đừng overengineer thông tin liên lạc giữa các chủ đề bằng cách sử dụng bộ nhớ chia sẻ và phức tạp, dễ bị lỗi đồng bộ hóa nguyên thủy, nhưng thay vì sử dụng truyền thông điệp giữa các goroutines (các luồng màu xanh lá cây) để các biến và dữ liệu có thể được sử dụng theo thứ tự giữa chúng.

Việc sử dụng chuỗi từ ở đây đáng chú ý, vì nó mô tả triết lý lấy cảm hứng từ khái niệm về kênh và kênh: Communicating Sequential Processes.

+0

Cảm ơn bạn đã đóng góp @SirDarius của bạn. Cho đến nay câu hỏi này tôi đã hỏi khiến tôi rất vui vẻ :) Tôi hy vọng mọi người cũng vậy. Nhưng, là câu trả lời của bạn cho câu hỏi của tôi 1) Không 2) Không? – honzajde

+0

Tôi có thể nói, vâng, và có, mặc dù tôi không chắc chắn cách phân tích kết luận của bạn có vẻ "thành ngữ" đối với các nhà phát triển Go, nếu bạn hiểu ý tôi là gì. Điều thiếu sót về cơ bản là khái niệm truyền quyền sở hữu. – SirDarius

+0

Phần này trong câu trả lời của bạn thực sự gây hiểu lầm: "... và cho đi quyền sở hữu bằng cách gửi giá trị hoặc con trỏ tới giá trị tới một goroutine khác thông qua cơ chế kênh" - không có khái niệm về quyền sở hữu trong thực tế và giả sử do đó dẫn đến điều kiện chủng tộc nếu gửi goroutine sửa đổi dữ liệu một lần nữa. – honzajde

1

1) Kết luận của tôi có đúng không?

Tôi nghĩ vậy, nếu nó có nghĩa là những gì tôi hy vọng. Lý do cho ngôn ngữ trong các thông số kỹ thuật sử dụng thuật ngữ "happenstance" là nó cung cấp một hình thức giao tiếp được xác định rõ ràng để thể hiện ý tưởng.

Sự cố với mô tả của bạn là bạn chưa xác định rõ ràng thứ tự xảy ra của mình. Tôi nghĩ rằng mặc dù bạn đang ngụ ý một trật tự. Nếu bạn ngụ ý rằng "hoạt động trong goroutine xảy ra trước khi goroutine hoạt động trên một điểm đồng bộ hóa cụ thể sẽ được hiển thị bởi goroutine b sau khi goroutine b cũng đã quan sát cùng một điểm đồng bộ hóa" - ngay cả ở đây, "điểm đồng bộ" được xác định kém - mặc dù tôi hy vọng bạn hiểu nó. Một điểm như vậy có thể được định nghĩa trong trường hợp xảy ra, như đặc tả.

2) Lời giải thích của tôi có giúp ích không?

Có thể, những người không quen thuộc với chủ đề hoặc đang đấu tranh với sự hiểu biết về kiểu diễn tả mô tả có thể tìm thấy mô tả của bạn dễ hiểu hơn. Tuy nhiên, có những hạn chế và các vấn đề thực tế tiềm ẩn trong việc áp dụng mô tả của bạn, như sau:

  • Bạn chưa xác định rõ rằng "gửi" bạn đang nói đến là điểm đồng bộ hóa. Nếu bạn có nghĩa là một gửi trên một kênh unbuffered, sau đó có, điều đó sẽ tạo ra một điểm đồng bộ hóa chia sẻ mà theo đặc điểm kỹ thuật giới thiệu một trật tự xảy ra nghiêm ngặt.
  • Trong khi, giả định ở trên là đúng, bạn đã mô tả một điểm đồng bộ hóa, điều này chỉ giải quyết một mặt của điểm của lời khuyên ban đầu. Lời khuyên ban đầu bao gồm khái niệm "chuyển quyền sở hữu" và ít có liên quan đến việc tạo các điểm đồng bộ hóa hoặc sự kiện xảy ra và nhiều hơn nữa để thực hiện việc duy trì mã lâu dài dựa trên bộ nhớ có khả năng chia sẻ. Khái niệm này là thay vì giữ lại quyền truy cập vào một số phân đoạn bộ nhớ ở hai nơi và tạo ra các điểm đồng bộ hóa được chia sẻ riêng biệt (như mutexes), thay vào đó có thể truyền, có thể là tham chiếu duy nhất cho đối tượng từ chủ sở hữu này sang chủ sở hữu khác. Thiết kế phần mềm theo cách này ngăn chặn sự sửa đổi ngẫu nhiên bên ngoài các điểm đồng bộ hóa, vốn thường được quan sát thấy trong phần mềm với việc sử dụng chi tiết các mutex và sử dụng rộng rãi bộ nhớ dùng chung.

Mutexes hoặc "điểm đồng bộ hóa rõ ràng" hoàn toàn trái ngược với lời khuyên - chúng là bộ nhớ dùng chung để giao tiếp điểm đồng bộ "giao tiếp bằng chia sẻ bộ nhớ", trong khi, mặc dù chúng có mutexes sâu dưới mui xe, các kênh là một cơ chế trừu tượng để truyền quyền sở hữu của một đối tượng (giá trị đã gửi) từ một goroutine (người gửi) đến một goroutine (bộ thu) khác. Điểm có là, bỏ qua cách các kênh được thực hiện, mà người dùng đã chia sẻ bộ nhớ (giá trị) bằng cách liên lạc nó từ một chủ sở hữu (goroutine a) đến một (goroutine b) khác. Nếu bạn đang sử dụng một kênh để gửi dữ liệu không liên quan để tạo điểm đồng bộ hóa, thì về cơ bản bạn đang sử dụng nó như một mutex và điều này gần gũi hơn với giao tiếp bằng cách chia sẻ bộ nhớ (tập trung vào kênh), thay vì chia sẻ bằng cách liên lạc giá trị).

Tôi hy vọng điều này sẽ hữu ích.

+0

Cảm ơn bạn đã chỉ ra các kênh đệm! Tôi đã cập nhật câu hỏi của mình để hiển nhiên rằng tôi đã giả định các kênh không bị chặn trước tiên. – honzajde

3

Có hai câu trong này; Để hiểu rõ hơn, chúng phải được xem xét riêng trước, và sau đó ghép lại với nhau, Vì vậy: Don't communicate by sharing memory; có nghĩa là các chủ đề khác nhau không được giao tiếp với nhau bằng cách tuân thủ nghiêm ngặt và dễ bị lỗi và các chính sách đồng bộ như rào cản bộ nhớ vv. rằng nó có thể được thực hiện, nhưng nó có thể sớm trở nên phức tạp và rất lỗi với các cuộc đua dữ liệu). Vì vậy, tránh tuân thủ các cấu trúc hiển thị thủ công, có lập trình chủ yếu đạt được thông qua việc đồng bộ hóa thích hợp trong các ngôn ngữ lập trình như Java.

share memory by communicating. có nghĩa là nếu một luồng đã thực hiện bất kỳ thay đổi nào (ghi) cho vùng bộ nhớ, nó sẽ truyền đạt cùng một vùng nhớ (memory area) với luồng quan tâm trong cùng vùng bộ nhớ đó; lưu ý rằng điều này đã hạn chế phạm vi bộ nhớ chỉ với hai luồng.

Bây giờ hãy đọc hai đoạn trên cùng với mô hình bộ nhớ golang, A send on a channel happens before the corresponding receive from that channel completes. Mối quan hệ xảy ra trước đó xác nhận rằng ghi bằng goroutine đầu tiên sẽ hiển thị với goroutine thứ hai nhận tham chiếu bộ nhớ ở đầu kia của kênh!

3

Hãy để tôi đi đơn giản và đến mức này.

Không giao tiếp bằng cách chia sẻ bộ nhớ.

Giống như khi bạn đang giao tiếp bằng cách sử dụng chủ đề, ví dụ bạn phải sử dụng các biến hoặc mutexes để khóa bộ nhớ để không cho phép ai đó đọc và ghi trên đó cho đến khi hoàn tất quá trình liên lạc.

Chia sẻ bộ nhớ bằng cách giao tiếp

Trong thói quen đi giá trị di chuyển trên các kênh truyền hình chứ không phải là ngăn chặn các bộ nhớ, gửi thông báo cho người nhận nhận được từ kênh đó và do đó nó chia sẻ bộ nhớ bằng cách giao tiếp với người nhận để có được từ một kênh.

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