2012-04-01 4 views
24

Có nhiều giải pháp hướng đến việc triển khai các luồng "không gian người dùng". Có thể là gorang.org goroutines, các chủ đề màu xanh lá cây của python, các đồng bộ của C#, các quá trình của erlang vv. Ý tưởng là cho phép lập trình đồng thời ngay cả với một số lượng giới hạn đơn hoặc giới hạn.Tại sao các chuỗi hệ điều hành được xem là đắt?

Điều tôi không hiểu là tại sao các chuỗi hệ điều hành lại quá đắt? Như tôi thấy nó, dù là cách nào bạn cũng phải lưu ngăn xếp của nhiệm vụ (chuỗi hệ điều hành, hoặc chủ đề của người dùng), đó là vài chục kilobyte, và bạn cần một bộ lập lịch để di chuyển giữa hai nhiệm vụ.

Hệ điều hành cung cấp cả hai chức năng này miễn phí. Tại sao các chuỗi hệ điều hành nên đắt hơn các luồng "xanh"? Lý do cho sự suy giảm hiệu suất giả định là gì do có một chuỗi hệ điều hành chuyên dụng cho mỗi "nhiệm vụ"?

+0

Chúng không chỉ được coi là đắt tiền, chúng được. Tôi tin rằng một số chủ đề màu xanh lá cây (Haskell's?) Chỉ nặng một vài kilobyte, nghĩa là nhỏ hơn hàng trăm lần. Một vấn đề khác: Python tiêu chuẩn không phải là màu xanh lá cây - họ có một số vấn đề với đa luồng do GIL, nhưng họ vẫn là chủ đề hệ điều hành thực sự (có thể bạn đang nghĩ về 'greenlets'? Đó là một câu chuyện khác nhau, và thực sự tương tự như màu xanh lá cây chủ đề). – delnan

+0

@delnan OK, tôi đã nghe điều đó. Nhưng tôi vẫn không chắc tại sao chúng đắt hơn. Cả hai cần phải lưu ngăn xếp và để làm chuyển đổi ngữ cảnh (bỏ qua GIL, có rất nhiều ví dụ không python). –

Trả lời

11

Tôi muốn sửa đổi Tudors câu trả lời là điểm khởi đầu tốt. Có hai chi phí chính của chủ đề:

  1. Bắt đầu và dừng chúng. Liên quan đến việc tạo ra một ngăn xếp và các đối tượng hạt nhân. Liên quan đến quá trình chuyển đổi hạt nhân và khóa hạt nhân toàn cầu.
  2. Giữ ngăn xếp của họ xung quanh.

(1) chỉ là vấn đề nếu bạn đang tạo và dừng tất cả thời gian. Điều này được giải quyết thông thường bằng cách sử dụng các nhóm luồng. Tôi xem vấn đề này được giải quyết thực tế. Lập kế hoạch một nhiệm vụ trên một hồ bơi thread thường không liên quan đến một chuyến đi đến hạt nhân mà làm cho nó rất nhanh. Chi phí trên là thứ tự của một vài hoạt động bộ nhớ liên động và một vài phân bổ.

(2) Điều này chỉ trở nên quan trọng nếu bạn có nhiều chủ đề (> 100 trở lên). Trong trường hợp này async IO là một phương tiện để loại bỏ các luồng. Tôi thấy rằng nếu bạn không có số lượng điên của các chủ đề IO đồng bộ bao gồm cả chặn là hơi nhanh hơn so với IO không đồng bộ (bạn đọc quyền: đồng bộ IO là nhanh hơn).

+1

(1) Tôi không chắc chắn lý do tại sao đối tượng hạt nhân đắt hơn các đối tượng không gian người dùng mà bạn cần khóa bất kỳ, và tất cả các khóa đều bị khóa xuống OS = kernle lock. Tôi không hiểu (2) bạn cần phải giữ ngăn xếp của họ dù sao đi nữa. –

+0

Không phải tất cả các giải pháp thay thế luồng đều giữ ngăn xếp xung quanh, ví dụ trong trường hợp tương lai/tác vụ chưa bắt đầu thực hiện. Ngoài ra, ngăn xếp thread OS có thể nặng hơn. .NET stack luôn cam kết 1MB bộ nhớ (không may). – usr

+2

Đối với (1): Khóa không đun sôi xuống ổ khóa hạt nhân. Nhiều tối ưu hóa có thể thực hiện đối với các khóa không được quản lý và/hoặc được lưu giữ trong thời gian ngắn. Đối tượng hạt nhân có nhiều chi phí hơn vì nhiều lý do (ví dụ chúng có thể được chia sẻ qua các quá trình, có thể có ACL, ...). Họ cũng yêu cầu chuyển đổi chế độ hạt nhân. – usr

4

Vấn đề bắt đầu luồng hạt nhân cho mỗi tác vụ nhỏ là nó phát sinh chi phí không đáng kể để bắt đầu và dừng, cùng với kích thước ngăn xếp cần thiết.

Đây là điểm quan trọng đầu tiên: các nhóm luồng tồn tại để bạn có thể tái chế các luồng, để tránh lãng phí thời gian bắt đầu cũng như lãng phí bộ nhớ cho các ngăn xếp của chúng. Thứ hai, nếu bạn tắt các chủ đề để làm I/O không đồng bộ, họ sẽ dành phần lớn thời gian của họ bị chặn chờ I/O để hoàn thành, do đó không có hiệu quả làm bất kỳ công việc và lãng phí bộ nhớ. Một lựa chọn tốt hơn là để có một công nhân xử lý nhiều cuộc gọi không đồng bộ (thông qua một số kỹ thuật lập kế hoạch dưới mui xe, chẳng hạn như ghép kênh), do đó tiết kiệm bộ nhớ và thời gian.

Một điều khiến chủ đề "xanh" nhanh hơn chủ đề hạt nhân là chúng là đối tượng không gian người dùng, được quản lý bởi máy ảo. Bắt đầu chúng là một cuộc gọi không gian người dùng, trong khi bắt đầu một luồng là một cuộc gọi không gian hạt nhân chậm hơn nhiều.

+0

Tôi không hiểu tại sao nó có nhiều chi phí hơn. Làm thế nào là nó khác nhau với chủ đề "xanh". Bạn phải giữ ngăn xếp của họ, vì vậy bạn đang lãng phí cùng một lượng bộ nhớ. –

+1

@ Chi-Lan: Chuỗi "xanh lục" có thể không phải là một chuỗi thực, mà là sự trừu tượng của một chuỗi. Một số chủ đề màu xanh lá cây có thể được lên kế hoạch thông minh trên cùng một chuỗi hạt nhân để sử dụng hiệu quả, ví dụ sử dụng các sợi cửa sổ để lập lịch trình hợp tác. – Tudor

+0

@ Chi-Lan: "xanh"/"nhẹ" chủ đề được thực hiện để tránh vấn đề này. Ví dụ trong số này là Haskell, Erlang và Python. –

0

Tôi nghĩ hai điều này ở các cấp độ khác nhau.

Thread hoặc Process là phiên bản chương trình đang được thực thi. Trong một quá trình/thread có nhiều thứ hơn trong đó. Thực hiện ngăn xếp, mở tệp, tín hiệu, trạng thái bộ xử lý và nhiều thứ khác.

Greentlet khác, nó chạy trong vm. Nó cung cấp một sợi trọng lượng nhẹ.Nhiều người trong số họ cung cấp một giả đồng thời (thường là trong một hoặc một vài chủ đề cấp hệ điều hành). Và thường họ cung cấp một phương pháp không khóa bằng cách truyền dữ liệu thay vì chia sẻ dữ liệu.

Vì vậy, hai điều tập trung khác nhau, vì vậy trọng lượng khác nhau.

Và trong tâm trí của tôi, greenlet nên được hoàn thành trong VM chứ không phải HĐH.

+1

greenlet có thể không có vm, xem golang.org –

6

Có nhiều giải pháp hướng tới việc triển khai các luồng "không gian người dùng". Có thể là gorang.org goroutines, các chủ đề màu xanh lá cây của python, các đồng bộ của C#, các quá trình của erlang vv. Ý tưởng là cho phép lập trình đồng thời ngay cả với một số lượng hạn chế hoặc một số chủ đề.

Đây là lớp trừu tượng. Nó dễ dàng hơn cho nhiều người để nắm bắt khái niệm này và sử dụng nó hiệu quả hơn trong nhiều tình huống. Nó cũng dễ dàng hơn cho nhiều máy (giả định một trừu tượng tốt), kể từ khi mô hình di chuyển từ chiều rộng để kéo trong nhiều trường hợp. Với pthreads (như một ví dụ), bạn có tất cả các điều khiển. Với các mô hình luồng khác, ý tưởng là sử dụng lại các luồng, cho quá trình tạo một tác vụ đồng thời không tốn kém và sử dụng một mô hình luồng hoàn toàn khác nhau. Nó dễ dàng hơn để tiêu hóa mô hình này; có ít hơn để tìm hiểu và đo lường, và kết quả nói chung là tốt.

Điều tôi không hiểu là tại sao các chuỗi hệ điều hành lại quá đắt? Như tôi thấy nó, dù là cách nào bạn cũng phải lưu ngăn xếp của nhiệm vụ (chuỗi hệ điều hành, hoặc chủ đề của người dùng), đó là vài chục kilobyte, và bạn cần một bộ lập lịch để di chuyển giữa hai nhiệm vụ.

Tạo chuỗi là tốn kém và ngăn xếp yêu cầu bộ nhớ. Đồng thời, nếu quá trình của bạn đang sử dụng nhiều luồng, thì chuyển đổi ngữ cảnh có thể giết hiệu suất. Vì vậy, các mô hình luồng nhẹ trở nên hữu ích vì một số lý do. Tạo một chuỗi hệ điều hành đã trở thành một giải pháp tốt cho các tác vụ vừa và lớn, lý tưởng ở các số thấp. Đó là hạn chế và tốn khá nhiều thời gian để duy trì.

Chủ đề công việc/luồng/chủ đề người dùng không cần phải lo lắng về việc chuyển đổi ngữ cảnh hoặc tạo chuỗi. Nó thường "tái sử dụng tài nguyên khi nó trở nên có sẵn, nếu nó chưa sẵn sàng ngay bây giờ - cũng, xác định số lượng chủ đề hoạt động cho máy này".

Chủ đề cấp cao hơn (IMO) rất đắt vì chúng không được các kỹ sư sử dụng đúng cách - hoặc có quá nhiều và có rất nhiều chuyển ngữ cảnh, cạnh tranh cho cùng một tập hợp tài nguyên, nhiệm vụ quá nhỏ. Phải mất nhiều thời gian hơn để hiểu cách sử dụng các luồng hệ điều hành một cách chính xác và cách áp dụng tốt nhất cho bối cảnh thực thi của chương trình.

Hệ điều hành cung cấp cả hai chức năng này miễn phí.

Chúng có sẵn, nhưng chúng không miễn phí. Chúng rất phức tạp và rất quan trọng đối với hiệu suất tốt. Khi bạn tạo một chuỗi hệ điều hành, nó được đưa ra thời gian 'sớm' - tất cả các quá trình 'thời gian được chia giữa các chủ đề. Đó không phải là trường hợp phổ biến với chủ đề người dùng. Nhiệm vụ thường được đặt ra khi tài nguyên không có sẵn. Điều này làm giảm chuyển đổi ngữ cảnh, bộ nhớ và tổng số luồng phải được tạo. Khi nhiệm vụ thoát ra, luồng này được gán cho một luồng khác.

xem xét tương tự này phân bố thời gian:

  • Giả sử bạn đang ở một casino. Có một số người muốn thẻ.
  • Bạn có một số đại lý cố định. Có ít đại lý hơn những người muốn thẻ.
  • Không phải lúc nào cũng có đủ thẻ cho mọi người tại bất kỳ thời điểm nào.
  • Mọi người cần tất cả các thẻ để hoàn thành trò chơi/tay của họ. Họ trả lại thẻ cho người chia bài khi trò chơi/bàn tay của họ hoàn tất.

Bạn sẽ yêu cầu các đại lý phân phối thẻ như thế nào?

Trong bộ lập lịch hệ điều hành, điều này sẽ dựa trên mức độ ưu tiên (luồng). Mỗi người sẽ được cấp một thẻ tại một thời điểm (thời gian CPU), và ưu tiên sẽ được đánh giá liên tục.

Những người đại diện cho công việc hoặc công việc của chủ đề. Các thẻ đại diện cho thời gian và tài nguyên. Các đại lý đại diện cho các chủ đề và tài nguyên.

Bạn sẽ xử lý nhanh nhất thế nào nếu có 2 đại lý và 3 người? và nếu có 5 đại lý và 500 người? Làm thế nào bạn có thể giảm thiểu chạy ra khỏi thẻ để đối phó? Với chủ đề, thêm thẻ và thêm đại lý không phải là giải pháp mà bạn có thể phân phối 'theo yêu cầu'. Thêm CPU tương đương với việc thêm đại lý. Thêm chủ đề tương đương với các đại lý giao dịch thẻ cho nhiều người hơn tại một thời điểm (tăng chuyển đổi ngữ cảnh). Có một số chiến lược để xử lý thẻ nhanh hơn, đặc biệt là sau khi bạn loại bỏ nhu cầu của mọi người đối với thẻ trong một khoảng thời gian nhất định. Nó sẽ không được nhanh hơn để đi đến một bảng và đối phó với một người hoặc người cho đến khi trò chơi của họ được hoàn thành nếu tỷ lệ đại lý cho người dân là 1/50? So sánh điều này để truy cập tất cả các bảng dựa trên mức độ ưu tiên và điều phối lượt truy cập giữa tất cả các đại lý (phương pháp tiếp cận hệ điều hành). Điều đó không ngụ ý hệ điều hành là ngu xuẩn - nó ngụ ý rằng việc tạo ra một chuỗi hệ điều hành là một kỹ sư bổ sung thêm nhiều người và nhiều bảng hơn, có khả năng nhiều hơn các đại lý có thể xử lý hợp lý. May mắn thay, các ràng buộc có thể được dỡ bỏ trong nhiều trường hợp bằng cách sử dụng các mô hình đa luồng khác và trừu tượng hóa cao hơn.

Tại sao chuỗi hệ điều hành lại đắt hơn chủ đề "xanh"? Lý do cho sự suy giảm hiệu suất giả định là gì do có một chuỗi hệ điều hành chuyên dụng cho mỗi "nhiệm vụ"?

Nếu bạn đã phát triển thư viện luồng cấp thấp quan trọng hiệu suất (ví dụ: pthreads), bạn sẽ nhận ra tầm quan trọng của việc sử dụng lại (và triển khai nó trong thư viện dưới dạng mô hình có sẵn cho người dùng). Từ góc độ đó, tầm quan trọng của các mô hình đa luồng bậc cao là một giải pháp/tối ưu hóa đơn giản và rõ ràng dựa trên việc sử dụng thế giới thực cũng như lý tưởng rằng thanh nhập cho việc áp dụng và sử dụng đa luồng có hiệu quả có thể được hạ xuống. Nó không phải là chúng đắt tiền - mô hình và hồ bơi của chủ đề nhẹ là một giải pháp tốt hơn cho nhiều vấn đề, và một trừu tượng thích hợp hơn cho các kỹ sư không hiểu chủ đề tốt. Sự phức tạp của đa luồng được đơn giản hóa rất nhiều (và thường có hiệu suất cao hơn trong việc sử dụng thế giới thực) theo mô hình này. Với các luồng hệ điều hành, bạn có nhiều quyền kiểm soát hơn, nhưng cần phải cân nhắc nhiều hơn để sử dụng chúng một cách hiệu quả nhất có thể - chú ý đến việc xem xét này có thể phản ánh đáng kể việc thực hiện/triển khai của chương trình. Với sự trừu tượng mức cao hơn, nhiều phức tạp này được giảm thiểu bằng cách thay đổi hoàn toàn dòng chảy của việc thực thi tác vụ (width vs pull).

6

Lưu ngăn xếp là tầm thường, bất kể kích thước của nó là gì - con trỏ ngăn xếp cần được lưu trong khối thông tin luồng trong hạt nhân, (vì vậy thường tiết kiệm phần lớn thanh ghi cũng vì chúng sẽ bị đẩy bởi bất kỳ thứ gì ngắt mềm/cứng khiến hệ điều hành được nhập vào).

Một vấn đề là phải có chu kỳ vòng bảo vệ để nhập hạt nhân từ người dùng. Đây là một chi phí cần thiết, nhưng gây phiền toái.Sau đó, trình điều khiển hoặc cuộc gọi hệ thống phải làm bất cứ điều gì đã được yêu cầu bởi ngắt và sau đó lên lịch/gửi các luồng vào bộ xử lý. Nếu điều này dẫn đến việc mua một luồng từ một quy trình bằng một luồng từ một luồng khác, thì một tải ngữ cảnh quá trình bổ sung cũng phải được hoán đổi. Thậm chí nhiều chi phí được thêm vào nếu hệ điều hành quyết định rằng một luồng đang chạy trên một lõi bộ vi xử lý khác là một trình xử lý ngắt ngắt được ngắt - lõi kia phải bị gián đoạn phần cứng, (đây là trên đầu ngắt cứng/mềm mà entred hệ điều hành ở nơi đầu tiên.

Vì vậy, một chạy lên lịch có thể là một hoạt động khá phức tạp.

'đề xanh' hoặc 'sợi' là, (thường), dự kiến ​​từ mã người dùng. một context- thay đổi dễ dàng hơn và rẻ hơn hệ điều hành gián đoạn vv vì không có chu trình vòng Wagnerian được yêu cầu trên mọi ngữ cảnh thay đổi, bối cảnh xử lý không thay đổi và chuỗi hệ điều hành chạy nhóm chỉ xanh không thay đổi.

Vì cái gì đó không có gì tồn tại, có vấn đề với các luồng màu xanh lá cây. Chúng được chạy bởi các luồng hệ điều hành 'thực'. Điều này có nghĩa rằng nếu một chuỗi 'xanh' trong một nhóm được chạy bởi một chuỗi hệ điều hành sẽ thực hiện cuộc gọi hệ điều hành chặn, tất cả các chuỗi màu xanh lá cây trong nhóm sẽ bị chặn. Điều này có nghĩa là các cuộc gọi đơn giản như sleep() phải được 'mô phỏng' bởi một máy trạng thái mang lại các luồng màu xanh lá cây khác, (vâng, giống như việc triển khai lại hệ điều hành). Tương tự như vậy, bất kỳ tín hiệu liên thread nào.

Ngoài ra, tất nhiên, chuỗi màu xanh lá cây không thể trả lời trực tiếp tín hiệu IO, vì vậy phần nào đánh bại điểm có bất kỳ chuỗi nào ở vị trí đầu tiên.

1

A person in Google shows an interesting approach.

Theo ông, chế độ kernel chuyển đổi bản thân không phải là nút cổ chai, và chi phí cốt lõi xảy ra trên SMP Scheduler. Và anh ấy tuyên bố rằng lịch trình M: N được hỗ trợ bởi hạt nhân sẽ không tốn kém, và điều này làm cho tôi mong đợi chung M: N luồng có sẵn trên mọi ngôn ngữ.