Giá trị trả về của bộ đếm thời gian luồng python
Phân luồng Python cho phép bạn chạy đồng thời các phần khác nhau của chương trình và có thể đơn giản hóa thiết kế của bạn. Nếu bạn đã có một số kinh nghiệm về Python và muốn tăng tốc chương trình của mình bằng các luồng, thì hướng dẫn này là dành cho bạn Show
Trong bài viết này, bạn sẽ học
Bài viết này giả định rằng bạn đã có kiến thức cơ bản về Python và bạn đang sử dụng ít nhất phiên bản 3. 6 để chạy các ví dụ. Nếu cần ôn lại, bạn có thể bắt đầu với Lộ trình học Python và bắt kịp tốc độ Nếu bạn không chắc mình muốn sử dụng Python 6, 8 hay 9, thì bạn có thể xem bài viết Tăng tốc chương trình Python của bạn với tính đồng thờiTất cả các nguồn được sử dụng trong hướng dẫn này đều có sẵn cho bạn trong repo Real Python GitHub Tiền thưởng miễn phí. 5 Suy nghĩ về Làm chủ Python, một khóa học miễn phí dành cho các nhà phát triển Python cho bạn thấy lộ trình và tư duy mà bạn sẽ cần để đưa các kỹ năng Python của mình lên một tầm cao mới Lấy bài kiểm tra. Kiểm tra kiến thức của bạn với bài kiểm tra tương tác “Python Threading” của chúng tôi. Sau khi hoàn thành, bạn sẽ nhận được điểm số để có thể theo dõi quá trình học tập của mình theo thời gian Lấy bài kiểm tra " Chủ đề là gì?Một luồng là một luồng thực thi riêng biệt. Điều này có nghĩa là chương trình của bạn sẽ có hai việc xảy ra cùng một lúc. Nhưng đối với hầu hết các triển khai Python 3, các luồng khác nhau không thực sự thực thi cùng một lúc. họ chỉ xuất hiện để Thật hấp dẫn khi nghĩ về phân luồng giống như có hai (hoặc nhiều) bộ xử lý khác nhau chạy trên chương trình của bạn, mỗi bộ xử lý thực hiện một nhiệm vụ độc lập cùng một lúc. Điều đó gần đúng. Các luồng có thể đang chạy trên các bộ xử lý khác nhau, nhưng chúng sẽ chỉ chạy một luồng tại một thời điểm Để nhiều tác vụ chạy đồng thời yêu cầu triển khai Python không chuẩn, viết một số mã của bạn bằng ngôn ngữ khác hoặc sử dụng 9 đi kèm với một số chi phí bổ sungDo cách triển khai CPython của Python hoạt động, luồng có thể không tăng tốc tất cả các tác vụ. Điều này là do các tương tác với GIL về cơ bản giới hạn một chuỗi Python chạy tại một thời điểm Các tác vụ dành nhiều thời gian chờ đợi các sự kiện bên ngoài thường là những ứng cử viên tốt cho luồng. Các sự cố yêu cầu tính toán CPU nặng và dành ít thời gian chờ đợi các sự kiện bên ngoài có thể không chạy nhanh hơn Điều này đúng với mã được viết bằng Python và chạy trên triển khai CPython tiêu chuẩn. Nếu chủ đề của bạn được viết bằng C, chúng có khả năng giải phóng GIL và chạy đồng thời. Nếu bạn đang chạy trên một triển khai Python khác, hãy kiểm tra cả tài liệu để xem nó xử lý các luồng như thế nào Nếu bạn đang chạy triển khai Python tiêu chuẩn, chỉ viết bằng Python và gặp sự cố liên quan đến CPU, bạn nên kiểm tra mô-đun 9 để thay thếKiến trúc chương trình của bạn để sử dụng phân luồng cũng có thể mang lại sự rõ ràng trong thiết kế. Hầu hết các ví dụ bạn sẽ tìm hiểu trong hướng dẫn này không nhất thiết phải chạy nhanh hơn vì chúng sử dụng các luồng. Sử dụng luồng trong chúng giúp làm cho thiết kế sạch hơn và dễ suy luận hơn Vì vậy, hãy ngừng nói về luồng và bắt đầu sử dụng nó Loại bỏ các quảng cáoBắt đầu một chủ đềBây giờ bạn đã có ý tưởng về chủ đề là gì, hãy tìm hiểu cách tạo một chủ đề. Thư viện chuẩn của Python cung cấp 6, chứa hầu hết các nguyên hàm mà bạn sẽ thấy trong bài viết này. 3, trong mô-đun này, gói gọn các luồng một cách độc đáo, cung cấp giao diện rõ ràng để làm việc với chúngĐể bắt đầu một chuỗi riêng biệt, bạn tạo một phiên bản 3 và sau đó yêu cầu nó cho 5 1Nếu bạn nhìn xung quanh các câu lệnh ghi nhật ký, bạn có thể thấy rằng phần 6 đang tạo và bắt đầu chuỗi 3Khi bạn tạo một 3, bạn truyền cho nó một hàm và một danh sách chứa các đối số của hàm đó. Trong trường hợp này, bạn đang yêu cầu 3 chạy 9 và chuyển nó 70 làm đối sốĐối với bài viết này, bạn sẽ sử dụng các số nguyên tuần tự làm tên cho chủ đề của mình. Có 71, trả về một tên duy nhất cho mỗi luồng, nhưng những tên này thường không ngắn và cũng không dễ đọc________ 89 bản thân nó không làm được gì nhiều. Nó chỉ đơn giản là ghi lại một số tin nhắn với một 73 ở giữa chúngKhi bạn chạy chương trình này như hiện tại (với dòng 20 được chú thích), đầu ra sẽ như thế này 1Bạn sẽ nhận thấy rằng phần 3 đã hoàn thành sau phần 75 trong mã của bạn. Bạn sẽ quay lại với lý do tại sao lại như vậy và nói về dòng số 20 bí ẩn trong phần tiếp theochủ đề daemonTrong khoa học máy tính, một 76 là một quá trình chạy trong nềnPython 6 có ý nghĩa cụ thể hơn đối với 76. Chuỗi 76 sẽ tắt ngay lập tức khi thoát khỏi chương trình. Một cách để suy nghĩ về những định nghĩa này là coi luồng 76 là luồng chạy trong nền mà không cần lo lắng về việc tắt nóNếu một chương trình đang chạy 91 mà không phải là 92, thì chương trình sẽ đợi các luồng đó hoàn thành trước khi kết thúc. Tuy nhiên, 91 là daemon, chỉ bị giết ở bất cứ đâu khi chương trình đang thoátHãy xem xét kỹ hơn một chút đầu ra của chương trình của bạn ở trên. Hai dòng cuối cùng là một chút thú vị. Khi bạn chạy chương trình, bạn sẽ nhận thấy rằng có một khoảng dừng (khoảng 2 giây) sau khi 94 đã in thông báo 95 của nó và trước khi luồng kết thúcViệc tạm dừng này là Python đang chờ chuỗi không phải daemon hoàn thành. Khi chương trình Python của bạn kết thúc, một phần của quy trình tắt máy là dọn sạch quy trình luồng Nếu bạn xem nguồn của Python 6, bạn sẽ thấy rằng 97 duyệt qua tất cả các luồng đang chạy và gọi 98 trên mọi luồng không có cờ 76 được đặtVì vậy, chương trình của bạn chờ để thoát vì bản thân luồng đang chờ trong chế độ ngủ. Ngay sau khi hoàn thành và in thông báo, 98 sẽ quay trở lại và chương trình có thể thoátThông thường, hành vi này là những gì bạn muốn, nhưng có các tùy chọn khác có sẵn cho chúng tôi. Trước tiên, hãy lặp lại chương trình với luồng 76. Bạn làm điều đó bằng cách thay đổi cách bạn xây dựng 3, thêm cờ 13
Khi bạn chạy chương trình bây giờ, bạn sẽ thấy đầu ra này ________số 8 Sự khác biệt ở đây là dòng cuối cùng của đầu ra bị thiếu. 9 không có cơ hội hoàn thành. Đó là một chuỗi 76, vì vậy khi 94 đến cuối mã của nó và chương trình muốn kết thúc, daemon đã bị giếtLoại bỏ các quảng cáox = threading.Thread(target=thread_function, args=(1,), daemon=True) 17 một chủ đềChủ đề daemon rất tiện dụng, nhưng còn khi bạn muốn đợi một chủ đề dừng lại thì sao? 7Để yêu cầu một luồng chờ một luồng khác kết thúc, bạn gọi ____298. Nếu bạn bỏ ghi chú dòng đó, luồng chính sẽ tạm dừng và đợi luồng 19 chạy hoàn tấtBạn đã kiểm tra điều này trên mã bằng luồng daemon hay luồng thông thường chưa? . Nếu bạn 98 một chủ đề, câu lệnh đó sẽ đợi cho đến khi một trong hai loại chủ đề kết thúcLàm việc với nhiều chủ đềMã ví dụ cho đến nay chỉ hoạt động với hai luồng. chủ đề chính và một chủ đề mà bạn đã bắt đầu với đối tượng 21Thông thường, bạn sẽ muốn bắt đầu một số chủ đề và để chúng thực hiện công việc thú vị. Hãy bắt đầu bằng cách xem xét cách khó hơn để thực hiện điều đó, sau đó bạn sẽ chuyển sang phương pháp dễ dàng hơn Cách khó hơn để bắt đầu nhiều chủ đề là cách bạn đã biết 9Mã này sử dụng cùng một cơ chế mà bạn đã thấy ở trên để bắt đầu chuỗi, tạo đối tượng 3, sau đó gọi 5. Chương trình giữ một danh sách các đối tượng 3 để có thể đợi chúng sau này bằng cách sử dụng 98Chạy mã này nhiều lần sẽ có thể tạo ra một số kết quả thú vị. Đây là một ví dụ đầu ra từ máy của tôi 1Nếu xem kỹ đầu ra, bạn sẽ thấy cả ba luồng bắt đầu theo thứ tự bạn có thể mong đợi, nhưng trong trường hợp này, chúng kết thúc theo thứ tự ngược lại. Nhiều lần chạy sẽ tạo ra các thứ tự khác nhau. Tìm thông báo 26 để cho bạn biết khi mỗi chủ đề hoàn thànhThứ tự chạy các luồng được xác định bởi hệ điều hành và có thể khá khó dự đoán. Nó có thể (và có khả năng sẽ) khác nhau giữa các lần chạy, vì vậy bạn cần lưu ý điều đó khi thiết kế các thuật toán sử dụng phân luồng May mắn thay, Python cung cấp cho bạn một số nguyên hàm mà bạn sẽ xem xét sau này để giúp phối hợp các luồng và khiến chúng chạy cùng nhau. Trước đó, hãy xem cách quản lý một nhóm chủ đề dễ dàng hơn một chút Sử dụng một x = threading.Thread(target=thread_function, args=(1,), daemon=True) 5Có một cách dễ dàng hơn để bắt đầu một nhóm chủ đề so với cách bạn đã thấy ở trên. Nó được gọi là 5 và là một phần của thư viện chuẩn trong 29 (kể từ Python 3. 2)Cách dễ nhất để tạo nó là với tư cách là người quản lý bối cảnh, sử dụng câu lệnh 30 để quản lý việc tạo và hủy nhómĐây là 94 từ ví dụ cuối cùng được viết lại để sử dụng một 5 2Mã này tạo một 5 với tư cách là người quản lý bối cảnh, cho nó biết có bao nhiêu luồng công nhân mà nó muốn trong nhóm. Sau đó, nó sử dụng ____634 để chuyển qua một thứ có thể lặp lại, trong trường hợp của bạn là ____635, chuyển từng thứ tới một luồng trong nhómSự kết thúc của khối 30 làm cho 5 thực hiện một 98 trên mỗi luồng trong nhóm. Chúng tôi thực sự khuyên bạn nên sử dụng 5 làm trình quản lý bối cảnh khi có thể để bạn không bao giờ quên 98 chủ đềGhi chú. Sử dụng một 5 có thể gây ra một số lỗi khó hiểuVí dụ: nếu bạn gọi một hàm không có tham số, nhưng bạn truyền tham số cho nó trong 34, luồng sẽ đưa ra một ngoại lệThật không may, 5 sẽ ẩn ngoại lệ đó và (trong trường hợp trên) chương trình kết thúc mà không có đầu ra. Điều này có thể khá khó hiểu khi gỡ lỗi lúc đầuChạy mã ví dụ đã sửa của bạn sẽ tạo ra kết quả giống như thế này 3Một lần nữa, hãy chú ý cách 304 hoàn thành trước 305. Việc lập lịch trình cho các luồng được thực hiện bởi hệ điều hành và không tuân theo một kế hoạch dễ hình dungLoại bỏ các quảng cáoĐiều kiện cuộc đuaTrước khi bạn chuyển sang một số tính năng khác có trong Python 6, hãy nói một chút về một trong những vấn đề khó khăn hơn mà bạn sẽ gặp phải khi viết các chương trình theo luồng. điều kiện cuộc đuaSau khi bạn đã biết điều kiện chủng tộc là gì và xem xét điều kiện xảy ra, bạn sẽ chuyển sang một số nguyên tắc do thư viện tiêu chuẩn cung cấp để ngăn chặn điều kiện chủng tộc xảy ra Điều kiện cạnh tranh có thể xảy ra khi hai hoặc nhiều luồng truy cập vào một phần dữ liệu hoặc tài nguyên được chia sẻ. Trong ví dụ này, bạn sẽ tạo một điều kiện cuộc đua lớn xảy ra mọi lúc, nhưng lưu ý rằng hầu hết các điều kiện cuộc đua không rõ ràng như vậy. Thông thường, chúng chỉ hiếm khi xảy ra và chúng có thể tạo ra kết quả khó hiểu. Như bạn có thể tưởng tượng, điều này khiến chúng khá khó gỡ lỗi May mắn thay, điều kiện cuộc đua này sẽ xảy ra mọi lúc và bạn sẽ xem chi tiết về nó để giải thích điều gì đang xảy ra Trong ví dụ này, bạn sẽ viết một lớp cập nhật cơ sở dữ liệu. Được rồi, bạn sẽ không thực sự có một cơ sở dữ liệu. bạn sẽ giả mạo nó, bởi vì đó không phải là điểm của bài viết này 307 của bạn sẽ có các phương thức 308 và 309 30 307 đang theo dõi một số duy nhất. 311. Đây sẽ là dữ liệu được chia sẻ mà bạn sẽ thấy điều kiện cuộc đua 308 chỉ cần khởi tạo 311 thành 0. Càng xa càng tốt 309 nhìn hơi lạ. Nó đang mô phỏng việc đọc một giá trị từ cơ sở dữ liệu, thực hiện một số tính toán trên đó và sau đó ghi một giá trị mới trở lại cơ sở dữ liệuTrong trường hợp này, đọc từ cơ sở dữ liệu chỉ có nghĩa là sao chép 311 vào một biến cục bộ. Việc tính toán chỉ là thêm một vào giá trị và sau đó 316 một chút. Cuối cùng, nó ghi lại giá trị bằng cách sao chép giá trị cục bộ trở lại 311Đây là cách bạn sẽ sử dụng 307 này 31Chương trình tạo một 5 với hai luồng và sau đó gọi 320 trên mỗi luồng, yêu cầu chúng chạy 321 320 có một chữ ký cho phép cả đối số vị trí và đối số được đặt tên được chuyển đến hàm đang chạy trong luồng 32Trong cách sử dụng ở trên, 323 được chuyển làm đối số vị trí đầu tiên và duy nhất cho 321. Bạn sẽ thấy ở phần sau của bài viết này, nơi bạn có thể truyền nhiều đối số theo cách tương tựVì mỗi chuỗi chạy 309 và 309 thêm một chuỗi vào 311, bạn có thể mong đợi 328 là 329 khi nó được in ra ở cuối. Nhưng bạn sẽ không xem xét ví dụ này nếu đó là trường hợp. Nếu bạn chạy đoạn mã trên, kết quả sẽ như thế này 33Bạn có thể đã mong đợi điều đó xảy ra, nhưng hãy xem chi tiết về những gì đang thực sự xảy ra ở đây, vì điều đó sẽ giúp giải pháp cho vấn đề này dễ hiểu hơn Loại bỏ các quảng cáomột chủ đềTrước khi bạn đi sâu vào vấn đề này với hai luồng, hãy quay lại và nói một chút về một số chi tiết về cách hoạt động của các luồng Bạn sẽ không đi sâu vào tất cả các chi tiết ở đây, vì điều đó không quan trọng ở cấp độ này. Chúng tôi cũng sẽ đơn giản hóa một số thứ theo cách không chính xác về mặt kỹ thuật nhưng sẽ cung cấp cho bạn ý tưởng đúng về những gì đang xảy ra Khi bạn yêu cầu 5 của mình chạy từng luồng, bạn sẽ cho nó biết chức năng nào sẽ chạy và những tham số nào cần truyền cho nó. 331Kết quả của việc này là mỗi luồng trong nhóm sẽ gọi 332. Lưu ý rằng 333 là tham chiếu đến một đối tượng 307 được tạo trong 94. Gọi 309 trên đối tượng đó gọi một phương thức thể hiện trên đối tượng đóMỗi luồng sẽ có một tham chiếu đến cùng một đối tượng 307, 333. Mỗi luồng cũng sẽ có một giá trị duy nhất, 323, để làm cho các báo cáo ghi nhật ký dễ đọc hơn một chútKhi luồng bắt đầu chạy 309, nó có phiên bản riêng của tất cả dữ liệu cục bộ cho hàm. Trong trường hợp của 309, đây là 342. Đây chắc chắn là một điều tốt. Nếu không, hai luồng chạy cùng một chức năng sẽ luôn gây nhầm lẫn cho nhau. Điều đó có nghĩa là tất cả các biến nằm trong phạm vi (hoặc cục bộ) của một hàm đều an toàn cho luồngBây giờ bạn có thể bắt đầu tìm hiểu xem điều gì sẽ xảy ra nếu bạn chạy chương trình ở trên với một chuỗi và một lệnh gọi duy nhất tới 309Hình ảnh dưới đây hướng dẫn thực thi 309 nếu chỉ có một luồng duy nhất được chạy. Câu lệnh được hiển thị ở bên trái, theo sau là sơ đồ hiển thị các giá trị trong 342 của luồng và 328 được chia sẻSơ đồ được bố trí sao cho thời gian tăng lên khi bạn di chuyển từ trên xuống dưới. Nó bắt đầu khi 304 được tạo và kết thúc khi nó bị chấm dứtKhi 304 bắt đầu, 349 bằng không. Dòng mã đầu tiên trong phương thức, 350, sao chép giá trị 0 vào biến cục bộ. Tiếp theo, nó tăng giá trị của 342 bằng câu lệnh 352. Bạn có thể thấy 311 trong 304 được đặt thành mộtTiếp theo, 73 được gọi, làm cho luồng hiện tại tạm dừng và cho phép các luồng khác chạy. Vì chỉ có một luồng trong ví dụ này nên điều này không có hiệu lựcKhi 304 thức dậy và tiếp tục, nó sẽ sao chép giá trị mới từ 342 sang 349, sau đó chuỗi hoàn thành. Bạn có thể thấy rằng 328 được đặt thành mộtCàng xa càng tốt. Bạn đã chạy 309 một lần và 349 đã được tăng lên mộthai chủ đềQuay trở lại điều kiện cuộc đua, hai luồng sẽ chạy đồng thời nhưng không đồng thời. Mỗi người sẽ có phiên bản 342 của riêng mình và mỗi người sẽ trỏ đến cùng một 333. Chính đối tượng 333 được chia sẻ này sẽ gây ra sự cốChương trình bắt đầu với 304 đang chạy 309Khi 304 gọi 73, nó cho phép luồng khác bắt đầu chạy. Đây là nơi mà mọi thứ trở nên thú vị 369 khởi động và thực hiện các thao tác tương tự. Nó cũng đang sao chép 328 vào 342 riêng tư của nó và 328 được chia sẻ này vẫn chưa được cập nhậtKhi 369 cuối cùng đi vào chế độ ngủ, 328 được chia sẻ vẫn chưa được sửa đổi ở mức 0 và cả hai phiên bản riêng của 342 đều có giá trị là một 304 hiện thức dậy và lưu phiên bản 342 của nó rồi chấm dứt, tạo cơ hội cuối cùng cho 369 để chạy. 369 không biết rằng 304 đã chạy và cập nhật 328 khi nó đang ngủ. Nó lưu trữ phiên bản 342 của nó vào 328, đồng thời đặt nó thành mộtHai luồng có quyền truy cập xen kẽ vào một đối tượng được chia sẻ duy nhất, ghi đè lên kết quả của nhau. Các điều kiện tương tự có thể phát sinh khi một luồng giải phóng bộ nhớ hoặc đóng một bộ xử lý tệp trước khi luồng kia truy cập xong. Loại bỏ các quảng cáoTại sao đây không phải là một ví dụ ngớ ngẩnVí dụ trên được tạo ra để đảm bảo rằng điều kiện chạy đua xảy ra mỗi khi bạn chạy chương trình của mình. Bởi vì hệ điều hành có thể hoán đổi một luồng bất kỳ lúc nào, nên có thể ngắt một câu lệnh như 384 sau khi nó đã đọc giá trị của 19 nhưng trước khi nó ghi lại giá trị đã tăngCác chi tiết về cách điều này xảy ra khá thú vị, nhưng không cần thiết cho phần còn lại của bài viết này, vì vậy vui lòng bỏ qua phần ẩn này Điều này thực sự hoạt động như thế nàoHiển thị/Ẩn Đoạn mã trên không hoàn toàn có sẵn như ban đầu bạn có thể nghĩ. Nó được thiết kế để bắt buộc một điều kiện cuộc đua mỗi khi bạn chạy nó, nhưng điều đó giúp giải quyết vấn đề dễ dàng hơn nhiều so với hầu hết các điều kiện cuộc đua Có hai điều cần lưu ý khi nghĩ về điều kiện cuộc đua
Hãy xem xét điều này một cách chi tiết. REPL bên dưới hiển thị một hàm nhận một tham số và tăng nó >>> 34Ví dụ REPL sử dụng 387 từ thư viện chuẩn Python để hiển thị các bước nhỏ hơn mà bộ xử lý thực hiện để thực hiện chức năng của bạn. Nó thực hiện một 388 của giá trị dữ liệu 19, nó thực hiện một 390 và sau đó nó sử dụng 391 để cộng các giá trị đó lại với nhauChúng tôi dừng lại ở đây vì một lý do cụ thể. Đây là điểm trong 309 ở trên nơi mà 73 buộc các chủ đề phải chuyển đổi. Hoàn toàn có khả năng, thỉnh thoảng, hệ điều hành sẽ chuyển các luồng tại điểm chính xác đó ngay cả khi không có 394, nhưng lệnh gọi tới 394 khiến điều đó xảy ra mọi lúcNhư bạn đã tìm hiểu ở trên, hệ điều hành có thể hoán đổi luồng bất kỳ lúc nào. Bạn đã đi xuống danh sách này đến tuyên bố được đánh dấu 396. Nếu hệ điều hành hoán đổi luồng này và chạy một luồng khác cũng sửa đổi 19, thì khi luồng này hoạt động trở lại, nó sẽ ghi đè lên 19 với một giá trị không chính xácVề mặt kỹ thuật, ví dụ này sẽ không có điều kiện chạy đua vì 19 là cục bộ của 100. Tuy nhiên, nó minh họa cách một luồng có thể bị gián đoạn trong một thao tác Python. Nhóm hoạt động TẢI, SỬA ĐỔI, CỬA HÀNG tương tự cũng xảy ra trên các giá trị chung và giá trị chung. Bạn có thể khám phá với mô-đun 387 và tự mình chứng minh điều đóRất hiếm khi xảy ra tình trạng cuộc đua như thế này, nhưng hãy nhớ rằng một sự kiện không thường xuyên xảy ra sau hàng triệu lần lặp lại có khả năng xảy ra. Sự hiếm có của các điều kiện chủng tộc này khiến chúng khó gỡ lỗi hơn nhiều so với các lỗi thông thường. Bây giờ hãy quay lại phần hướng dẫn được lên lịch thường xuyên của bạn Bây giờ bạn đã thấy một điều kiện chủng tộc đang hoạt động, hãy cùng tìm hiểu cách giải quyết chúng Đồng bộ hóa Cơ bản Sử dụng x = threading.Thread(target=thread_function, args=(1,), daemon=True) 102Có một số cách để tránh hoặc giải quyết các điều kiện chủng tộc. Bạn sẽ không xem xét tất cả chúng ở đây, nhưng có một số được sử dụng thường xuyên. Hãy bắt đầu với 102Để giải quyết tình trạng tương tranh của bạn ở trên, bạn cần tìm cách chỉ cho phép một chuỗi tại một thời điểm vào phần đọc-sửa-ghi trong mã của bạn. Cách phổ biến nhất để làm điều này được gọi là 102 trong Python. Trong một số ngôn ngữ khác, ý tưởng tương tự này được gọi là 105. Mutex đến từ Loại trừ MUTual, đó chính xác là những gì mà 102 làmMột 102 là một đối tượng hoạt động giống như thẻ hành lang. Chỉ một chủ đề tại một thời điểm có thể có 102. Bất kỳ chủ đề nào khác muốn có 102 phải đợi cho đến khi chủ sở hữu của 102 từ bỏ nóCác chức năng cơ bản để làm điều này là 111 và 112. Một chủ đề sẽ gọi 113 để lấy khóa. Nếu khóa đã được giữ, chuỗi cuộc gọi sẽ đợi cho đến khi nó được giải phóng. Có một điểm quan trọng ở đây. Nếu một luồng nhận được khóa nhưng không bao giờ trả lại, chương trình của bạn sẽ bị kẹt. Bạn sẽ đọc thêm về điều này sauMay mắn thay, 102 của Python cũng sẽ hoạt động như một trình quản lý bối cảnh, vì vậy bạn có thể sử dụng nó trong câu lệnh 30 và nó sẽ tự động được giải phóng khi khối 30 thoát ra vì bất kỳ lý do gìHãy nhìn vào 307 với một 102 được thêm vào nó. Chức năng gọi vẫn giữ nguyên 35Ngoài việc thêm một loạt nhật ký gỡ lỗi để bạn có thể thấy khóa rõ ràng hơn, thay đổi lớn ở đây là thêm một thành viên có tên là 119, là một đối tượng 120. 119 này được khởi tạo ở trạng thái không khóa và bị khóa và giải phóng bởi câu lệnh 30Điều đáng chú ý ở đây là chuỗi chạy chức năng này sẽ giữ lại 102 đó cho đến khi hoàn tất việc cập nhật cơ sở dữ liệu. Trong trường hợp này, điều đó có nghĩa là nó sẽ giữ 102 trong khi sao chép, cập nhật, ngủ và sau đó ghi giá trị trở lại cơ sở dữ liệuNếu bạn chạy phiên bản này với ghi nhật ký được đặt ở mức cảnh báo, bạn sẽ thấy điều này 36Nhìn kìa. Chương trình của bạn cuối cùng cũng hoạt động Bạn có thể bật ghi nhật ký đầy đủ bằng cách đặt mức thành 125 bằng cách thêm câu lệnh này sau khi bạn định cấu hình đầu ra ghi nhật ký trong 94 37Chạy chương trình này với tính năng ghi nhật ký 125 được bật trông như thế này 38Trong kết quả này, bạn có thể thấy 305 nhận được khóa và vẫn đang giữ nó khi chuyển sang chế độ ngủ. 304 sau đó bắt đầu và cố gắng lấy cùng một khóa. Vì 305 vẫn đang giữ nên 304 phải đợi. Đây là loại trừ lẫn nhau mà một 102 cung cấpNhiều ví dụ trong phần còn lại của bài viết này sẽ có ghi nhật ký cấp độ 133 và 125. Nói chung, chúng tôi sẽ chỉ hiển thị đầu ra ở cấp độ 133, vì nhật ký của 125 có thể khá dài. Hãy thử các chương trình có đăng nhập và xem những gì họ làmLoại bỏ các quảng cáoBế tắcTrước khi tiếp tục, bạn nên xem xét một vấn đề thường gặp khi sử dụng 137. Như bạn đã thấy, nếu 102 đã được mua, lệnh gọi thứ hai đến 111 sẽ đợi cho đến khi chuỗi đang giữ 102 gọi 112. Bạn nghĩ điều gì sẽ xảy ra khi bạn chạy mã này 39Khi chương trình gọi 142 lần thứ hai, nó bị treo chờ 102 được giải phóng. Trong ví dụ này, bạn có thể khắc phục bế tắc bằng cách loại bỏ cuộc gọi thứ hai, nhưng bế tắc thường xảy ra từ một trong hai điều nhỏ
Tình huống đầu tiên đôi khi xảy ra, nhưng việc sử dụng 102 làm trình quản lý bối cảnh sẽ giảm đáng kể tần suất. Bạn nên viết mã bất cứ khi nào có thể để sử dụng trình quản lý ngữ cảnh, vì chúng giúp tránh các tình huống mà một ngoại lệ bỏ qua bạn qua lệnh gọi 112Vấn đề thiết kế có thể phức tạp hơn một chút ở một số ngôn ngữ. Rất may, luồng Python có một đối tượng thứ hai, được gọi là 148, được thiết kế cho tình huống này. Nó cho phép một thread tới 111 và 148 nhiều lần trước khi nó gọi 112. Chủ đề đó vẫn được yêu cầu gọi 112 bằng số lần nó gọi là 111, nhưng dù sao thì nó cũng phải làm như vậy 102 và 148 là hai trong số các công cụ cơ bản được sử dụng trong lập trình luồng để ngăn chặn điều kiện chủng tộc. Có một số khác hoạt động theo những cách khác nhau. Trước khi bạn xem xét chúng, hãy chuyển sang một lĩnh vực vấn đề hơi khácLuồng sản xuất-người tiêu dùngVấn đề Nhà sản xuất-Người tiêu dùng là một vấn đề khoa học máy tính tiêu chuẩn được sử dụng để xem xét các vấn đề về luồng hoặc quá trình đồng bộ hóa. Bạn sẽ xem xét một biến thể của nó để có một số ý tưởng về những gì nguyên thủy mà mô-đun Python 6 cung cấpTrong ví dụ này, bạn sẽ tưởng tượng một chương trình cần đọc tin nhắn từ mạng và ghi chúng vào đĩa. Chương trình không yêu cầu một tin nhắn khi nó muốn. Nó phải đang lắng nghe và chấp nhận tin nhắn khi chúng đến. Các tin nhắn sẽ không đến với tốc độ đều đặn mà sẽ đến từng đợt. Phần này của chương trình được gọi là nhà sản xuất Mặt khác, khi bạn có một tin nhắn, bạn cần ghi nó vào cơ sở dữ liệu. Truy cập cơ sở dữ liệu chậm, nhưng đủ nhanh để theo kịp tốc độ trung bình của tin nhắn. Nó không đủ nhanh để theo kịp khi một loạt tin nhắn đến. Bộ phận này là người tiêu dùng Ở giữa nhà sản xuất và người tiêu dùng, bạn sẽ tạo một 157 sẽ là phần thay đổi khi bạn tìm hiểu về các đối tượng đồng bộ hóa khác nhauĐó là bố cục cơ bản. Hãy xem xét một giải pháp bằng cách sử dụng 102. Nó không hoạt động hoàn hảo, nhưng nó sử dụng các công cụ mà bạn đã biết, vì vậy đây là một nơi tốt để bắt đầuNhà sản xuất-Người tiêu dùng Sử dụng x = threading.Thread(target=thread_function, args=(1,), daemon=True) 102Vì đây là một bài viết về Python 6 và vì bạn vừa đọc về nguyên hàm của 102, hãy thử giải quyết vấn đề này với hai luồng bằng cách sử dụng một hoặc hai 102.Thiết kế chung là có một luồng 163 đọc từ mạng giả mạo và đặt thông báo vào một 157 10Để tạo một tin nhắn giả mạo, 163 nhận một số ngẫu nhiên từ một đến một trăm. Nó gọi 166 trên 167 để gửi nó đến 168 163 cũng sử dụng giá trị 170 để báo hiệu cho người tiêu dùng dừng lại sau khi đã gửi mười giá trị. Điều này hơi khó xử, nhưng đừng lo, bạn sẽ thấy các cách để loại bỏ giá trị 170 này sau khi bạn làm việc qua ví dụ nàyỞ phía bên kia của 167 là người tiêu dùng 11 168 đọc một tin nhắn từ 167 và ghi nó vào một cơ sở dữ liệu giả mạo, trong trường hợp này chỉ là in nó ra màn hình. Nếu nó nhận được giá trị 170, nó sẽ trả về từ hàm, điều này sẽ kết thúc luồngTrước khi bạn xem phần thực sự thú vị, phần 157, đây là phần 94, tạo ra những chủ đề này 12Điều này trông khá quen thuộc vì nó gần với mã 94 trong các ví dụ trướcHãy nhớ rằng bạn có thể bật ghi nhật ký 125 để xem tất cả các thông báo ghi nhật ký bằng cách bỏ ghi chú dòng này 13Có thể đáng để xem qua các thông báo ghi nhật ký của 125 để xem chính xác vị trí mỗi chuỗi lấy và giải phóng các khóaBây giờ chúng ta hãy xem 157 truyền tin nhắn từ 163 đến 168 14ồ. Đó là rất nhiều mã. Một tỷ lệ phần trăm khá cao trong số đó chỉ là ghi lại các câu lệnh để dễ dàng xem điều gì đang xảy ra khi bạn chạy nó. Đây là cùng một mã với tất cả các câu lệnh ghi nhật ký đã bị xóa 15Điều đó có vẻ dễ quản lý hơn một chút. 157 trong phiên bản mã này của bạn có ba thành viên
192 khởi tạo ba thành viên này và sau đó gọi 111 trên 189. Đây là trạng thái bạn muốn bắt đầu. 163 được phép thêm tin nhắn mới, nhưng 168 cần đợi cho đến khi có tin nhắn 197 và 198 gần như đối lập nhau. 197 cuộc gọi 111 trên 01. Đây là cuộc gọi sẽ khiến 168 đợi cho đến khi có tin nhắnKhi 168 đã có được 189, nó sẽ sao chép giá trị trong 185 và sau đó gọi 112 trên 186. Mở khóa này là điều cho phép 163 chèn thông báo tiếp theo vào 167Trước khi bạn tiếp tục với 166, có một điều gì đó tế nhị đang diễn ra trong 197 mà bạn rất dễ bỏ sót. Nó có vẻ hấp dẫn để loại bỏ 12 và chỉ để hàm kết thúc bằng 13. Xem liệu bạn có thể tìm ra lý do tại sao bạn không muốn làm điều đó trước khi tiếp tụcĐây là câu trả lời. Ngay khi 168 gọi 15, nó có thể được hoán đổi và 163 có thể bắt đầu chạy. Điều đó có thể xảy ra trước khi 112 trở lại. Điều này có nghĩa là có một khả năng nhỏ là khi hàm trả về 18, đó thực sự có thể là tin nhắn tiếp theo được tạo, vì vậy bạn sẽ mất tin nhắn đầu tiên. Đây là một ví dụ khác về điều kiện chủng tộcChuyển sang 166, bạn có thể thấy mặt trái của giao dịch. 163 sẽ gọi điều này bằng một tin nhắn. Nó sẽ lấy 186, đặt 185 và gọi 112 sau đó là 01, điều này sẽ cho phép 168 đọc giá trị đóHãy chạy mã có ghi nhật ký được đặt thành 133 và xem nó trông như thế nào 16Lúc đầu, bạn có thể thấy lạ khi nhà sản xuất nhận được hai tin nhắn trước khi người tiêu dùng thậm chí chạy. Nếu bạn nhìn lại 163 và 166, bạn sẽ nhận thấy rằng nơi duy nhất mà nó chờ đợi một 102 là khi nó cố gắng đưa thông báo vào đường dẫn. Việc này được thực hiện sau khi 163 nhận được thông báo và ghi lại rằng nó đã nhận được thông báo đóKhi 163 cố gắng gửi tin nhắn thứ hai này, nó sẽ gọi 166 lần thứ hai và nó sẽ chặnHệ điều hành có thể hoán đổi các luồng bất cứ lúc nào, nhưng nó thường cho phép mỗi luồng có một khoảng thời gian hợp lý để chạy trước khi hoán đổi nó. Đó là lý do tại sao 163 thường chạy cho đến khi nó chặn lệnh gọi thứ hai tới 166Tuy nhiên, khi một luồng bị chặn, hệ điều hành sẽ luôn hoán đổi nó và tìm một luồng khác để chạy. Trong trường hợp này, chuỗi duy nhất khác có bất kỳ việc gì phải làm là 168 168 gọi 197, đọc tin nhắn và gọi 112 trên 186, do đó cho phép 163 chạy lại vào lần tiếp theo các chuỗi được hoán đổiLưu ý rằng tin nhắn đầu tiên là 41 và đó chính xác là những gì mà 168 đã đọc, mặc dù 163 đã tạo ra tin nhắn 44Mặc dù nó hoạt động cho thử nghiệm hạn chế này, nhưng nó không phải là một giải pháp tuyệt vời cho vấn đề người sản xuất-người tiêu dùng nói chung vì nó chỉ cho phép một giá trị duy nhất trong quy trình tại một thời điểm. Khi 163 nhận được một loạt tin nhắn, nó sẽ không có nơi nào để đặt chúngHãy chuyển sang một cách tốt hơn để giải quyết vấn đề này, sử dụng 46Loại bỏ các quảng cáoNhà sản xuất-Người tiêu dùng Sử dụng x = threading.Thread(target=thread_function, args=(1,), daemon=True) 46Nếu bạn muốn có thể xử lý nhiều giá trị trong quy trình cùng một lúc, bạn sẽ cần cấu trúc dữ liệu cho quy trình cho phép số lượng tăng và giảm khi dữ liệu được sao lưu từ 163Thư viện chuẩn của Python có một mô-đun 49, đến lượt nó, có một lớp 46. Hãy thay đổi 157 để sử dụng một 46 thay vì chỉ một biến được bảo vệ bởi một 102. Bạn cũng sẽ sử dụng một cách khác để dừng các worker thread bằng cách sử dụng một nguyên hàm khác từ Python 6, một 55Hãy bắt đầu với 55. Đối tượng 57 cho phép một luồng báo hiệu một 58 trong khi nhiều luồng khác có thể chờ đợi điều đó xảy ra. Cách sử dụng chính trong mã này là các luồng đang chờ sự kiện không nhất thiết phải dừng việc chúng đang làm, chúng chỉ cần thỉnh thoảng kiểm tra trạng thái của 55Việc kích hoạt sự kiện có thể là nhiều thứ. Trong ví dụ này, luồng chính sẽ ngủ một lúc và sau đó 61 nó 17Những thay đổi duy nhất ở đây là việc tạo đối tượng 58 trên dòng 8, chuyển 58 làm tham số trên dòng 10 và 11, và phần cuối cùng trên dòng 13 đến 15, ngủ trong một giây, ghi nhật ký và sau đó gọi 163 cũng không phải thay đổi quá nhiều 18Bây giờ nó sẽ lặp lại cho đến khi thấy rằng sự kiện đã được đặt trên dòng 3. Nó cũng không còn đặt giá trị 170 vào 167 168 phải thay đổi thêm một chút 19Trong khi bạn phải lấy mã liên quan đến giá trị 170, bạn phải thực hiện một điều kiện 70 phức tạp hơn một chút. Nó không chỉ lặp cho đến khi 58 được đặt, mà còn cần tiếp tục lặp cho đến khi 167 được làm trốngĐảm bảo hàng đợi trống trước khi người tiêu dùng kết thúc sẽ ngăn chặn một vấn đề thú vị khác. Nếu 168 thoát trong khi 167 có tin nhắn trong đó, có hai điều tồi tệ có thể xảy ra. Đầu tiên là bạn mất những tin nhắn cuối cùng đó, nhưng điều nghiêm trọng hơn là 163 có thể bị bắt khi cố gắng thêm một tin nhắn vào hàng đợi đầy đủ và không bao giờ quay lạiĐiều này xảy ra nếu 58 được kích hoạt sau khi 163 đã kiểm tra điều kiện 78 nhưng trước khi nó gọi 79Nếu điều đó xảy ra, người tiêu dùng có thể thức dậy và thoát ra với hàng đợi vẫn đầy đủ. Sau đó, 163 sẽ gọi 166 sẽ đợi cho đến khi có chỗ trống trên hàng đợi cho tin nhắn mới. 168 đã thoát, vì vậy điều này sẽ không xảy ra và 163 sẽ không thoátPhần còn lại của 168 sẽ trông quen thuộcTuy nhiên, 157 đã thay đổi đáng kể 0Bạn có thể thấy rằng 157 là một lớp con của 87. 46 có một tham số tùy chọn khi khởi tạo để chỉ định kích thước tối đa của hàng đợiNếu bạn cung cấp một số dương cho ________ 089, nó sẽ giới hạn hàng đợi ở số lượng phần tử đó, khiến cho 90 bị chặn cho đến khi có ít hơn ________ 089 phần tử. Nếu bạn không chỉ định 89, thì hàng đợi sẽ phát triển đến giới hạn bộ nhớ máy tính của bạn 197 và 166 nhỏ hơn nhiều. Về cơ bản, họ bọc 95 và 90 trên 46. Bạn có thể tự hỏi tất cả các mã khóa ngăn chặn các chủ đề gây ra tình trạng cuộc đua đã đi đâuCác nhà phát triển cốt lõi đã viết thư viện tiêu chuẩn biết rằng 46 thường được sử dụng trong môi trường đa luồng và đã kết hợp tất cả mã khóa đó bên trong chính 46. 46 là chủ đề an toànChạy chương trình này trông giống như sau 1Nếu bạn đọc qua đầu ra trong ví dụ của tôi, bạn có thể thấy một số điều thú vị đang xảy ra. Ngay ở trên cùng, bạn có thể thấy 163 phải tạo năm tin nhắn và đặt bốn tin nhắn trong số đó vào hàng đợi. Nó đã bị hệ điều hành tráo đổi trước khi nó có thể đặt cái thứ nămSau đó, 168 đã chạy và gửi tin nhắn đầu tiên. Nó in ra thông báo đó cũng như độ sâu của hàng đợi tại thời điểm đó 2Đây là cách bạn biết rằng tin nhắn thứ năm vẫn chưa được gửi đến ________ 2167. Hàng đợi giảm xuống kích thước ba sau khi một tin nhắn bị xóa. Bạn cũng biết rằng 49 có thể chứa mười tin nhắn, vì vậy chuỗi 163 không bị chặn bởi 49. Nó đã bị tráo đổi bởi hệ điều hànhGhi chú. Đầu ra của bạn sẽ khác. Đầu ra của bạn sẽ thay đổi từ lần chạy này sang lần chạy khác. Đó là phần thú vị khi làm việc với các chủ đề Khi chương trình bắt đầu kết thúc, bạn có thể thấy luồng chính tạo ra 58 khiến cho 163 thoát ngay lập tức không. 168 vẫn còn rất nhiều việc phải làm, vì vậy nó sẽ tiếp tục chạy cho đến khi dọn sạch 167Hãy thử chơi với các kích thước hàng đợi khác nhau và các cuộc gọi tới 73 trong 163 hoặc 168 để mô phỏng thời gian truy cập mạng hoặc ổ đĩa lâu hơn tương ứng. Ngay cả những thay đổi nhỏ đối với các yếu tố này của chương trình cũng sẽ tạo ra sự khác biệt lớn trong kết quả của bạnĐây là một giải pháp tốt hơn nhiều cho vấn đề người sản xuất-người tiêu dùng, nhưng bạn có thể đơn giản hóa nó hơn nữa. 157 thực sự không cần thiết cho vấn đề này. Khi bạn gỡ bỏ ghi nhật ký, nó sẽ trở thành một 87Đây là mã cuối cùng trông như thế nào khi sử dụng trực tiếp 87 3Điều đó dễ đọc hơn và cho thấy cách sử dụng các nguyên hàm tích hợp sẵn của Python có thể đơn giản hóa một vấn đề phức tạp 102 và 46 là các lớp tiện dụng để giải quyết các vấn đề tương tranh, nhưng có những lớp khác do thư viện chuẩn cung cấp. Trước khi bạn kết thúc hướng dẫn này, hãy thực hiện một cuộc khảo sát nhanh về một số trong số chúngLoại bỏ các quảng cáođối tượng luồngCó một vài nguyên mẫu khác được cung cấp bởi mô-đun Python 6. Mặc dù bạn không cần những thứ này cho các ví dụ trên, nhưng chúng có thể hữu ích trong các trường hợp sử dụng khác nhau, vì vậy bạn nên làm quen với chúngđèn hiệuĐối tượng Python 6 đầu tiên cần xem xét là 21. Một 22 là một bộ đếm có một vài thuộc tính đặc biệt. Đầu tiên là việc đếm là nguyên tử. Điều này có nghĩa là đảm bảo rằng hệ điều hành sẽ không tráo đổi luồng khi đang tăng hoặc giảm bộ đếmBộ đếm nội bộ được tăng lên khi bạn gọi 112 và giảm đi khi bạn gọi 111Thuộc tính đặc biệt tiếp theo là nếu một luồng gọi 111 khi bộ đếm bằng 0, luồng đó sẽ chặn cho đến khi một luồng khác gọi 112 và tăng bộ đếm lên mộtSemaphores thường được sử dụng để bảo vệ tài nguyên có dung lượng hạn chế. Một ví dụ sẽ là nếu bạn có một nhóm kết nối và muốn giới hạn kích thước của nhóm đó ở một số cụ thể hẹn giờ 27 là một cách để lên lịch một chức năng được gọi sau một khoảng thời gian nhất định đã trôi qua. Bạn tạo một 28 bằng cách chuyển trong một số giây để đợi và một chức năng để gọi 4Bạn bắt đầu 28 bằng cách gọi 5. Hàm sẽ được gọi trên một luồng mới vào một thời điểm nào đó sau thời gian đã chỉ định, nhưng hãy lưu ý rằng không có gì hứa hẹn rằng nó sẽ được gọi chính xác vào thời điểm bạn muốnNếu bạn muốn dừng một 28 mà bạn đã bắt đầu, bạn có thể hủy nó bằng cách gọi cho 32. Gọi 32 sau khi 28 đã kích hoạt không làm gì cả và không tạo ra ngoại lệMột 28 có thể được sử dụng để nhắc người dùng hành động sau một khoảng thời gian cụ thể. Nếu người dùng thực hiện hành động trước khi 28 hết hạn, thì có thể gọi 32Rào chắnMột 38 có thể được sử dụng để đồng bộ hóa một số luồng cố định. Khi tạo một 39, người gọi phải chỉ định có bao nhiêu luồng sẽ được đồng bộ hóa trên đó. Mỗi luồng gọi 40 trên 39. Tất cả chúng sẽ vẫn bị chặn cho đến khi số lượng chủ đề được chỉ định đang chờ và sau đó tất cả sẽ được giải phóng cùng một lúcHãy nhớ rằng các luồng được lên lịch bởi hệ điều hành, vì vậy, mặc dù tất cả các luồng được giải phóng đồng thời, chúng sẽ được lên lịch để chạy từng luồng một Một cách sử dụng cho 39 là cho phép một nhóm các luồng tự khởi tạo. Để các luồng chờ trên 39 sau khi chúng được khởi tạo sẽ đảm bảo rằng không có luồng nào bắt đầu chạy trước khi tất cả các luồng kết thúc quá trình khởi tạo của chúngSự kết luận. Luồng trong PythonBây giờ bạn đã thấy phần lớn những gì Python 6 cung cấp và một số ví dụ về cách xây dựng các chương trình luồng và các vấn đề mà chúng giải quyết. Bạn cũng đã thấy một vài ví dụ về các vấn đề phát sinh khi viết và gỡ lỗi các chương trình luồng.Nếu bạn muốn khám phá các tùy chọn khác để đồng thời trong Python, hãy xem Tăng tốc chương trình Python của bạn với đồng thời Nếu bạn muốn tìm hiểu sâu về mô-đun 8, hãy đọc Async IO trong Python. Hướng dẫn hoàn chỉnhDù bạn làm gì, giờ đây bạn đã có thông tin và sự tự tin cần thiết để viết chương trình bằng luồng Python Đặc biệt cảm ơn độc giả JL Diaz đã giúp làm sạch phần giới thiệu Lấy bài kiểm tra. Kiểm tra kiến thức của bạn với bài kiểm tra tương tác “Python Threading” của chúng tôi. Sau khi hoàn thành, bạn sẽ nhận được điểm số để có thể theo dõi quá trình học tập của mình theo thời gian Lấy bài kiểm tra " Đánh dấu là đã hoàn thành Xem ngay Hướng dẫn này có một khóa học video liên quan do nhóm Real Python tạo. Xem nó cùng với hướng dẫn bằng văn bản để hiểu sâu hơn. Tạo luồng trong Python 🐍 Thủ thuật Python 💌 Nhận một Thủ thuật Python ngắn và hấp dẫn được gửi đến hộp thư đến của bạn vài ngày một lần. Không có thư rác bao giờ. Hủy đăng ký bất cứ lúc nào. Được quản lý bởi nhóm Real Python Gửi cho tôi thủ thuật Python » Về Jim Anderson Jim đã lập trình trong một thời gian dài bằng nhiều ngôn ngữ. Anh ấy đã làm việc trên các hệ thống nhúng, xây dựng các hệ thống xây dựng phân tán, quản lý nhà cung cấp nước ngoài và tham gia rất nhiều cuộc họp » Thông tin thêm về JimMỗi hướng dẫn tại Real Python được tạo bởi một nhóm các nhà phát triển để nó đáp ứng các tiêu chuẩn chất lượng cao của chúng tôi. Các thành viên trong nhóm đã làm việc trong hướng dẫn này là Aldren Brad Joanna Bậc thầy Kỹ năng Python trong thế giới thực Với quyền truy cập không giới hạn vào Python thực Tham gia với chúng tôi và có quyền truy cập vào hàng nghìn hướng dẫn, khóa học video thực hành và cộng đồng các Pythonistas chuyên gia Nâng cao kỹ năng Python của bạn » Bậc thầy Kỹ năng Python trong thế giới thực Tham gia với chúng tôi và có quyền truy cập vào hàng ngàn hướng dẫn, khóa học video thực hành và cộng đồng Pythonistas chuyên gia Nâng cao kỹ năng Python của bạn » Bạn nghĩ sao? Đánh giá bài viết này Tweet Chia sẻ Chia sẻ EmailBài học số 1 hoặc điều yêu thích mà bạn đã học được là gì? Mẹo bình luận. Những nhận xét hữu ích nhất là những nhận xét được viết với mục đích học hỏi hoặc giúp đỡ các sinh viên khác. Nhận các mẹo để đặt câu hỏi hay và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi Chuỗi Python có thể trả về giá trị không?Một chuỗi không thể trả về giá trị trực tiếp . Phương thức start() trên một luồng gọi phương thức run() của luồng thực thi mã của chúng ta trong một luồng thực thi mới. Đến lượt phương thức run() có thể gọi một hàm đích, nếu được định cấu hình.
Làm thế nào để bộ đếm thời gian luồng hoạt động Python?Phân luồng trong Python Timer() bắt đầu sau độ trễ được xác định là đối số . Do đó, lớp Timer gọi chính nó trì hoãn việc thực hiện thao tác sau trong cùng một khoảng thời gian được chỉ định.
Hạn chế chính của luồng với Python là gì?Do cách triển khai CPython của Python hoạt động, luồng có thể không tăng tốc tất cả các tác vụ . Điều này là do các tương tác với GIL về cơ bản giới hạn một chuỗi Python chạy tại một thời điểm. Các tác vụ dành nhiều thời gian chờ đợi các sự kiện bên ngoài thường là những ứng cử viên tốt cho luồng. |