Tôi nghĩ rằng điểm của một máy tính đa lõi là nó có thể chạy nhiều luồng cùng lúc. Trong trường hợp đó, nếu bạn có một máy lõi tứ, thì điểm nào có nhiều hơn 4 luồng chạy cùng một lúc? Họ sẽ không đánh cắp thời gian (Tài nguyên CPU) với nhau chứ?
Tôi nghĩ rằng điểm của một máy tính đa lõi là nó có thể chạy nhiều luồng cùng lúc. Trong trường hợp đó, nếu bạn có một máy lõi tứ, thì điểm nào có nhiều hơn 4 luồng chạy cùng một lúc? Họ sẽ không đánh cắp thời gian (Tài nguyên CPU) với nhau chứ?
Câu trả lời:
Câu trả lời xoay quanh mục đích của các luồng, đó là sự song song: để chạy một vài dòng thực thi riêng biệt cùng một lúc. Trong một hệ thống 'lý tưởng', bạn sẽ có một luồng thực thi trên mỗi lõi: không bị gián đoạn. Trong thực tế, đây không phải là trường hợp. Ngay cả khi bạn có bốn lõi và bốn luồng làm việc, tiến trình của bạn và các luồng của nó sẽ liên tục bị tắt cho các tiến trình và luồng khác. Nếu bạn đang chạy bất kỳ HĐH hiện đại nào, mọi tiến trình đều có ít nhất một luồng và nhiều luồng có nhiều hơn. Tất cả các quá trình này đang chạy cùng một lúc. Bạn có thể có hàng trăm luồng tất cả đang chạy trên máy của bạn ngay bây giờ. Bạn sẽ không bao giờ gặp phải tình huống một luồng chạy mà không có thời gian 'bị đánh cắp' từ nó. (Chà, bạn có thể nếu nó chạy thời gian thực, nếu bạn đang sử dụng HĐH thời gian thực hoặc thậm chí trên Windows, hãy sử dụng mức độ ưu tiên của luồng thời gian thực. Nhưng nó rất hiếm.)
Với nền tảng đó, câu trả lời: Có, hơn bốn luồng trên máy bốn lõi thực sự có thể mang đến cho bạn tình huống chúng 'đánh cắp thời gian của nhau', nhưng chỉ khi mỗi luồng riêng lẻ cần CPU 100% . Nếu một luồng không hoạt động 100% (vì một luồng UI có thể không hoặc một luồng thực hiện một lượng công việc nhỏ hoặc chờ đợi một thứ khác) thì một luồng khác được lên lịch thực sự là một tình huống tốt.
Nó thực sự phức tạp hơn thế:
Điều gì nếu bạn có năm bit công việc mà tất cả cần phải được thực hiện cùng một lúc? Nó có ý nghĩa hơn để chạy tất cả chúng cùng một lúc, hơn là chạy bốn trong số chúng và sau đó chạy thứ năm sau đó.
Thật hiếm khi một luồng thực sự cần CPU 100%. Ví dụ, thời điểm nó sử dụng I / O của đĩa hoặc mạng, nó có thể có khả năng dành thời gian chờ đợi mà không làm gì hữu ích. Đây là một tình huống rất phổ biến.
Nếu bạn có công việc cần phải chạy, một cơ chế phổ biến là sử dụng một luồng. Có vẻ như có ý nghĩa khi có cùng số lượng luồng như lõi, tuy nhiên, luồng xử lý .Net có tới 250 luồng có sẵn trên mỗi bộ xử lý . Tôi không chắc tại sao họ làm điều này, nhưng tôi đoán là sẽ làm với kích thước của các nhiệm vụ được đưa ra để chạy trên các luồng.
Vì vậy: đánh cắp thời gian không phải là một điều xấu (và cũng không thực sự là trộm cắp: đó là cách hệ thống được cho là hoạt động.) Viết các chương trình đa luồng của bạn dựa trên loại công việc mà các luồng sẽ làm, có thể không phải là CPU -Đến. Chỉ ra số lượng chủ đề bạn cần dựa trên hồ sơ và đo lường. Bạn có thể thấy hữu ích hơn khi suy nghĩ về các nhiệm vụ hoặc công việc, thay vì các chủ đề: viết các đối tượng của công việc và đưa chúng vào một nhóm để được chạy. Cuối cùng, trừ khi chương trình của bạn thực sự quan trọng về hiệu suất, đừng quá lo lắng :)
Chỉ vì một luồng tồn tại không có nghĩa là nó luôn hoạt động. Nhiều ứng dụng của các luồng liên quan đến một số luồng sẽ đi ngủ cho đến khi chúng phải làm gì đó - ví dụ, các luồng kích hoạt đầu vào của người dùng để đánh thức, xử lý và quay trở lại giấc ngủ.
Về cơ bản, các luồng là các tác vụ riêng lẻ có thể hoạt động độc lập với nhau, không cần phải biết về tiến trình của một tác vụ khác. Hoàn toàn có thể có nhiều thứ trong số này hơn là bạn có khả năng chạy đồng thời; chúng vẫn hữu ích cho sự thuận tiện ngay cả khi đôi khi chúng phải xếp hàng chờ nhau.
Vấn đề là, mặc dù không nhận được bất kỳ sự tăng tốc thực sự nào khi số lượng luồng vượt quá số lượng lõi, bạn có thể sử dụng các luồng để loại bỏ các đoạn logic không cần phải phụ thuộc lẫn nhau.
Ngay cả trong một ứng dụng phức tạp vừa phải, sử dụng một luồng duy nhất sẽ cố gắng thực hiện mọi thứ một cách nhanh chóng để tạo ra "dòng chảy" mã của bạn. Chủ đề duy nhất dành phần lớn thời gian để thăm dò ý kiến này, kiểm tra điều đó, gọi các thói quen một cách có điều kiện khi cần thiết, và thật khó để nhìn thấy bất cứ điều gì ngoại trừ một chút vụn vặt.
Đối chiếu điều này với trường hợp bạn có thể dành các luồng cho các tác vụ để khi nhìn vào bất kỳ luồng nào, bạn có thể thấy luồng đó đang làm gì. Chẳng hạn, một luồng có thể chặn chờ đầu vào từ ổ cắm, phân tích luồng thành tin nhắn, lọc tin nhắn và khi có thông báo hợp lệ xuất hiện, hãy chuyển nó sang một số luồng công nhân khác. Chuỗi công nhân có thể làm việc trên các đầu vào từ một số nguồn khác. Mã cho mỗi trong số này sẽ thể hiện một luồng rõ ràng, có mục đích, mà không cần phải kiểm tra rõ ràng rằng không có gì khác để làm.
Phân vùng công việc theo cách này cho phép ứng dụng của bạn dựa vào hệ điều hành để lên lịch cho những việc cần làm tiếp theo với cpu, do đó bạn không phải thực hiện kiểm tra có điều kiện rõ ràng ở mọi nơi trong ứng dụng của mình về những gì có thể chặn và những gì đã sẵn sàng để xử lý.
Nếu một luồng đang chờ một tài nguyên (chẳng hạn như tải một giá trị từ RAM vào một thanh ghi, I / O đĩa, truy cập mạng, khởi chạy một quy trình mới, truy vấn cơ sở dữ liệu hoặc đợi đầu vào của người dùng), bộ xử lý có thể hoạt động trên một luồng khác nhau và trở về luồng đầu tiên sau khi tài nguyên có sẵn. Điều này giúp giảm thời gian CPU không hoạt động, vì CPU có thể thực hiện hàng triệu hoạt động thay vì ngồi không.
Xem xét một chủ đề cần đọc dữ liệu từ một ổ đĩa cứng. Trong năm 2014, lõi xử lý điển hình hoạt động ở tốc độ 2,5 GHz và có thể thực hiện 4 lệnh mỗi chu kỳ. Với thời gian chu kỳ là 0,4 ns, bộ xử lý có thể thực hiện 10 lệnh mỗi nano giây. Với thời gian tìm kiếm ổ cứng cơ học thông thường là khoảng 10 mili giây, bộ xử lý có khả năng thực hiện 100 triệu hướng dẫn trong thời gian cần thiết để đọc giá trị từ ổ cứng. Có thể có những cải tiến hiệu suất đáng kể với các ổ đĩa cứng có bộ đệm nhỏ (bộ đệm 4 MB) và ổ đĩa lai có dung lượng lưu trữ vài GB, vì độ trễ dữ liệu để đọc hoặc đọc tuần tự từ phần lai có thể nhanh hơn vài bậc.
Lõi bộ xử lý có thể chuyển đổi giữa các luồng (chi phí để tạm dừng và tiếp tục một luồng là khoảng 100 chu kỳ xung nhịp) trong khi luồng đầu tiên chờ đầu vào có độ trễ cao (bất cứ thứ gì đắt hơn đăng ký (1 xung nhịp) và RAM (5 nano giây) I / O đĩa, truy cập mạng (độ trễ 250ms), đọc dữ liệu từ đĩa CD hoặc bus chậm hoặc cuộc gọi cơ sở dữ liệu. Có nhiều luồng hơn lõi có nghĩa là công việc hữu ích có thể được thực hiện trong khi các nhiệm vụ có độ trễ cao được giải quyết.
CPU có một bộ lập lịch luồng chỉ định mức độ ưu tiên cho mỗi luồng và cho phép một luồng ngủ, sau đó tiếp tục lại sau một thời gian định trước. Công việc của bộ lập lịch xử lý là giảm bớt việc đập, điều này sẽ xảy ra nếu mỗi luồng thực hiện chỉ 100 lệnh trước khi được đưa vào chế độ ngủ lại. Chi phí hoạt động của các luồng chuyển đổi sẽ làm giảm tổng thông lượng hữu ích của lõi bộ xử lý.
Vì lý do này, bạn có thể muốn chia nhỏ vấn đề của mình thành số lượng chủ đề hợp lý. Nếu bạn đang viết mã để thực hiện phép nhân ma trận, việc tạo một luồng trên mỗi ô trong ma trận đầu ra có thể là quá mức, trong khi một luồng trên mỗi hàng hoặc mỗi n hàng trong ma trận đầu ra có thể giảm chi phí tạo ra, tạm dừng và tiếp tục các luồng.
Đây cũng là lý do tại sao dự đoán chi nhánh là quan trọng. Nếu bạn có một câu lệnh if yêu cầu tải một giá trị từ RAM nhưng phần thân của câu lệnh if và khác sử dụng các giá trị đã được tải vào các thanh ghi, bộ xử lý có thể thực thi một hoặc cả hai nhánh trước khi điều kiện được đánh giá. Khi điều kiện trả về, bộ xử lý sẽ áp dụng kết quả của nhánh tương ứng và loại bỏ nhánh kia. Thực hiện công việc có khả năng vô dụng ở đây có lẽ tốt hơn là chuyển sang một chủ đề khác, điều này có thể dẫn đến đập.
Khi chúng tôi chuyển từ bộ xử lý lõi đơn tốc độ cao sang bộ xử lý đa lõi, thiết kế chip đã tập trung vào việc nhồi nhét nhiều lõi hơn mỗi lần chết, cải thiện việc chia sẻ tài nguyên trên chip giữa các lõi, thuật toán dự đoán nhánh tốt hơn, chuyển đổi luồng tốt hơn, và lập lịch trình tốt hơn.
Hầu hết các câu trả lời ở trên nói về hiệu suất và hoạt động đồng thời. Tôi sẽ tiếp cận điều này từ một góc độ khác.
Chúng ta hãy xem trường hợp của một chương trình mô phỏng thiết bị đầu cuối đơn giản. Bạn phải làm những điều sau đây:
(Trình giả lập thiết bị đầu cuối thực sự làm được nhiều hơn, bao gồm cả khả năng lặp lại nội dung bạn nhập vào màn hình, nhưng chúng tôi sẽ chuyển qua điều đó ngay bây giờ.)
Bây giờ vòng lặp để đọc từ xa rất đơn giản, theo mã giả sau đây:
while get-character-from-remote:
print-to-screen character
Vòng lặp để giám sát bàn phím và gửi cũng đơn giản:
while get-character-from-keyboard:
send-to-remote character
Tuy nhiên, vấn đề là bạn phải làm điều này đồng thời. Mã bây giờ phải trông giống như thế này nếu bạn không có luồng:
loop:
check-for-remote-character
if remote-character-is-ready:
print-to-screen character
check-for-keyboard-entry
if keyboard-is-ready:
send-to-remote character
Logic, ngay cả trong ví dụ đơn giản hóa có chủ ý này không tính đến sự phức tạp của truyền thông trong thế giới thực, cũng khá khó hiểu. Tuy nhiên, với luồng, ngay cả trên một lõi đơn, hai vòng mã giả có thể tồn tại độc lập mà không xen kẽ logic của chúng. Vì cả hai luồng sẽ chủ yếu là ràng buộc I / O, nên chúng không gây tải nặng cho CPU, mặc dù, nói đúng ra, sẽ lãng phí tài nguyên CPU hơn so với vòng lặp tích hợp.
Bây giờ tất nhiên việc sử dụng trong thế giới thực phức tạp hơn so với ở trên. Nhưng sự phức tạp của vòng lặp tích hợp tăng theo cấp số nhân khi bạn thêm nhiều mối quan tâm hơn vào ứng dụng. Logic trở nên phân mảnh hơn bao giờ hết và bạn phải bắt đầu sử dụng các kỹ thuật như máy trạng thái, coroutines, et al để có thể quản lý mọi thứ. Quản lý, nhưng không thể đọc được. Threading giữ cho mã dễ đọc hơn.
Vậy tại sao bạn không sử dụng luồng?
Chà, nếu các tác vụ của bạn bị ràng buộc CPU thay vì ràng buộc I / O, thì luồng thực sự làm chậm hệ thống của bạn. Hiệu suất sẽ bị. Rất nhiều, trong nhiều trường hợp. ("Đập" là một vấn đề phổ biến nếu bạn thả quá nhiều luồng bị ràng buộc CPU. Bạn sẽ mất nhiều thời gian hơn để thay đổi các luồng hoạt động hơn là bạn tự chạy nội dung của các luồng.) đơn giản đến mức tôi đã cố tình chọn một ví dụ đơn giản (và không thực tế). Nếu bạn muốn lặp lại những gì đã gõ vào màn hình thì bạn đã có một thế giới đau thương mới khi bạn giới thiệu khóa tài nguyên được chia sẻ. Chỉ với một tài nguyên được chia sẻ, đây không phải là vấn đề quá lớn, nhưng nó bắt đầu trở thành một vấn đề lớn hơn và lớn hơn khi bạn có nhiều tài nguyên hơn để chia sẻ.
Vì vậy, cuối cùng, luồng là về nhiều thứ. Ví dụ, đó là về việc làm cho các quy trình ràng buộc I / O phản ứng nhanh hơn (ngay cả khi tổng thể kém hiệu quả hơn) như một số người đã nói. Đó cũng là về việc làm cho logic dễ theo dõi hơn (nhưng chỉ khi bạn giảm thiểu trạng thái chia sẻ). Đó là về rất nhiều thứ, và bạn phải quyết định xem những ưu điểm của nó có vượt trội hơn những nhược điểm của nó trong từng trường hợp hay không.
Mặc dù bạn chắc chắn có thể sử dụng các luồng để tăng tốc tính toán tùy thuộc vào phần cứng của bạn, một trong những công dụng chính của chúng là làm nhiều việc một lúc vì lý do thân thiện với người dùng.
Ví dụ: nếu bạn phải thực hiện một số xử lý trong nền và vẫn đáp ứng với đầu vào UI, bạn có thể sử dụng các luồng. Không có chủ đề, giao diện người dùng sẽ bị treo mỗi khi bạn cố gắng thực hiện bất kỳ xử lý nặng nào.
Cũng xem câu hỏi liên quan này: Sử dụng thực tế cho chủ đề
Tôi hoàn toàn không đồng ý với khẳng định của @ kyoryu rằng con số lý tưởng là một luồng trên mỗi CPU.
Hãy nghĩ về nó theo cách này: tại sao chúng ta có các hệ điều hành đa xử lý? Trong hầu hết lịch sử máy tính, gần như tất cả các máy tính đều có một CPU. Tuy nhiên, từ những năm 1960 trở đi, tất cả các máy tính "thực" đều có hệ điều hành đa xử lý (hay còn gọi là đa tác vụ).
Bạn chạy nhiều chương trình để một chương trình có thể chạy trong khi các chương trình khác bị chặn cho những thứ như IO.
hãy đặt các đối số sang một bên về việc các phiên bản Windows trước NT có đa tác vụ hay không. Kể từ đó, mọi hệ điều hành thực sự đều có đa tác vụ. Một số người không tiếp xúc với người dùng, nhưng dù sao thì nó cũng làm những việc như nghe radio trên điện thoại di động, nói chuyện với chip GPS, chấp nhận nhập chuột, v.v.
Chủ đề chỉ là nhiệm vụ hiệu quả hơn một chút. Không có sự khác biệt cơ bản giữa một nhiệm vụ, quy trình và luồng.
CPU là một thứ khủng khiếp để lãng phí, vì vậy hãy chuẩn bị sẵn rất nhiều thứ khi bạn có thể.
Tôi sẽ đồng ý rằng với hầu hết các ngôn ngữ thủ tục, C, C ++, Java, v.v., viết mã an toàn chủ đề phù hợp là rất nhiều công việc. Với CPU 6 lõi trên thị trường hiện nay và CPU 16 lõi không còn xa nữa, tôi hy vọng rằng mọi người sẽ tránh xa các ngôn ngữ cũ này, vì đa luồng ngày càng trở thành một yêu cầu quan trọng.
Không đồng ý với @kyoryu chỉ là IMHO, phần còn lại là sự thật.
Hãy tưởng tượng một máy chủ Web phải phục vụ một số lượng yêu cầu tùy ý. Bạn phải phục vụ các yêu cầu song song vì nếu không, mỗi yêu cầu mới phải đợi cho đến khi tất cả các yêu cầu khác được hoàn thành (bao gồm gửi phản hồi qua Internet). Trong trường hợp này, hầu hết các máy chủ web có số lõi ít hơn số lượng yêu cầu họ thường phục vụ.
Nó cũng giúp nhà phát triển máy chủ dễ dàng hơn: Bạn chỉ phải viết một chương trình luồng phục vụ yêu cầu, bạn không phải suy nghĩ về việc lưu trữ nhiều yêu cầu, thứ tự bạn phục vụ, v.v.
Nhiều luồng sẽ ngủ, chờ người dùng nhập, I / O và các sự kiện khác.
Chủ đề có thể giúp đáp ứng trong các ứng dụng UI. Ngoài ra, bạn có thể sử dụng các chủ đề để có được nhiều công việc hơn từ lõi của bạn. Ví dụ, trên một lõi đơn, bạn có thể có một luồng thực hiện IO và một luồng khác thực hiện một số tính toán. Nếu nó là một luồng đơn, thì về cơ bản, lõi có thể không hoạt động khi chờ IO hoàn thành. Đó là một ví dụ cấp độ khá cao, nhưng các chủ đề chắc chắn có thể được sử dụng để đập cpu của bạn khó hơn một chút.
Bộ xử lý, hoặc CPU, là chip vật lý được cắm vào hệ thống. Một bộ xử lý có thể có nhiều lõi (lõi là một phần của chip có khả năng thực hiện các hướng dẫn). Một lõi có thể xuất hiện với hệ điều hành dưới dạng nhiều bộ xử lý ảo nếu nó có khả năng thực thi đồng thời nhiều luồng (một luồng là một chuỗi các lệnh).
Một quy trình là một tên khác cho một ứng dụng. Nói chung, các quá trình là độc lập với nhau. Nếu một quá trình chết, nó không gây ra quá trình khác cũng chết. Có thể cho các quá trình giao tiếp hoặc chia sẻ tài nguyên như bộ nhớ hoặc I / O.
Mỗi quá trình có một không gian địa chỉ và ngăn xếp riêng biệt. Một tiến trình có thể chứa nhiều luồng, mỗi luồng có thể thực hiện các lệnh cùng một lúc. Tất cả các luồng trong một tiến trình chia sẻ cùng một không gian địa chỉ, nhưng mỗi luồng sẽ có ngăn xếp riêng.
Hy vọng với những định nghĩa và nghiên cứu sâu hơn bằng cách sử dụng những nguyên tắc cơ bản này sẽ giúp bạn hiểu hơn.
Việc sử dụng lý tưởng của các chủ đề là, thực sự, một cho mỗi lõi.
Tuy nhiên, trừ khi bạn độc quyền sử dụng IO không đồng bộ / không chặn, rất có thể bạn sẽ có các luồng bị chặn trên IO tại một số điểm, điều này sẽ không sử dụng CPU của bạn.
Ngoài ra, các ngôn ngữ lập trình điển hình làm cho việc sử dụng 1 luồng trên mỗi CPU trở nên khó khăn hơn. Các ngôn ngữ được thiết kế xung quanh đồng thời (như Erlang) có thể giúp dễ dàng hơn khi không sử dụng các luồng bổ sung.
Cách một số API được thiết kế, bạn không có lựa chọn nào khác ngoài việc chạy chúng trong một luồng riêng biệt (bất cứ điều gì có hoạt động chặn). Một ví dụ sẽ là các thư viện HTTP của Python (AFAIK).
Thông thường, đây không phải là vấn đề lớn (nếu đó là sự cố, HĐH hoặc API sẽ xuất xưởng với chế độ hoạt động không đồng bộ thay thế, ví dụ select(2)
:), bởi vì điều đó có thể có nghĩa là luồng sẽ ngủ trong khi chờ I / O hoàn thành. Mặt khác, nếu một cái gì đó đang thực hiện một tính toán nặng nề, bạn phải đặt nó trong một luồng riêng biệt hơn là luồng GUI (trừ khi bạn thích ghép kênh thủ công).
Tôi biết đây là một câu hỏi siêu cũ với nhiều câu trả lời hay, nhưng tôi ở đây để chỉ ra một điều quan trọng trong môi trường hiện tại:
Nếu bạn muốn thiết kế một ứng dụng cho đa luồng, bạn không nên thiết kế cho một cài đặt phần cứng cụ thể. Công nghệ CPU đã tiến bộ khá nhanh trong nhiều năm và số lượng lõi đang tăng đều đặn. Nếu bạn cố tình thiết kế ứng dụng của mình sao cho nó chỉ sử dụng 4 luồng, thì bạn có khả năng tự giới hạn mình trong một hệ thống octa-core (ví dụ). Bây giờ, ngay cả các hệ thống 20 lõi đều có sẵn trên thị trường, vì vậy một thiết kế như vậy chắc chắn gây hại nhiều hơn là tốt.
Đáp lại phỏng đoán đầu tiên của bạn: các máy đa lõi có thể chạy đồng thời nhiều tiến trình, không chỉ nhiều luồng của một tiến trình đơn lẻ.
Để trả lời câu hỏi đầu tiên của bạn: điểm của nhiều luồng thường là thực hiện đồng thời nhiều tác vụ trong một ứng dụng. Các ví dụ kinh điển trên mạng là chương trình gửi và nhận thư, và máy chủ web nhận và gửi yêu cầu trang. (Lưu ý rằng về cơ bản không thể giảm một hệ thống như Windows để chỉ chạy một luồng hoặc thậm chí chỉ một tiến trình. Chạy Trình quản lý tác vụ Windows và thông thường bạn sẽ thấy một danh sách dài các quy trình đang hoạt động, nhiều quy trình sẽ chạy nhiều luồng. )
Để trả lời cho câu hỏi thứ hai của bạn: hầu hết các quy trình / luồng không bị ràng buộc CPU (nghĩa là không chạy liên tục và không bị gián đoạn), nhưng thay vào đó hãy dừng lại và chờ đợi thường xuyên để I / O kết thúc. Trong thời gian chờ đợi đó, các quy trình / luồng khác có thể chạy mà không "đánh cắp" từ mã chờ (ngay cả trên một máy lõi đơn).
Một luồng là một sự trừu tượng cho phép Bạn viết mã đơn giản như một chuỗi hoạt động, hoàn toàn không biết rằng mã được thực thi xen kẽ với mã khác, hoặc chờ đợi IO, hoặc (có thể nhận thức rõ hơn một chút) chờ đợi các luồng khác sự kiện hoặc tin nhắn.
Vấn đề là phần lớn các lập trình viên không hiểu cách thiết kế một máy trạng thái. Việc có thể đặt mọi thứ trong luồng riêng của nó giúp người lập trình không phải suy nghĩ về cách biểu diễn hiệu quả trạng thái của các tính toán đang thực hiện khác nhau để chúng có thể bị gián đoạn và sau đó được tiếp tục.
Ví dụ, xem xét nén video, một nhiệm vụ rất cpu. Nếu bạn đang sử dụng công cụ gui, có lẽ bạn muốn giao diện vẫn phản hồi (hiển thị tiến trình, trả lời các yêu cầu hủy, thay đổi kích thước cửa sổ, v.v.). Vì vậy, bạn thiết kế phần mềm mã hóa của mình để xử lý một đơn vị lớn (một hoặc nhiều khung hình) tại một thời điểm và chạy nó trong luồng riêng, tách biệt với UI.
Tất nhiên một khi bạn nhận ra rằng thật tuyệt khi có thể lưu trạng thái mã hóa đang tiến hành để bạn có thể đóng chương trình để khởi động lại hoặc chơi một trò chơi ngốn tài nguyên, bạn nhận ra rằng bạn nên học cách thiết kế các máy trạng thái từ bắt đầu Dù vậy, hoặc bạn quyết định thiết kế một vấn đề hoàn toàn mới về quá trình ngủ đông hệ điều hành của bạn để bạn có thể tạm dừng và tiếp tục các ứng dụng riêng lẻ vào đĩa ...