Kwargs pool đa xử lý python
Vì Python được phát triển lần đầu tiên cách đây 29 năm nên không có gì ngạc nhiên khi nó được thiết kế như một ngôn ngữ lập trình tuyến tính khi CPU lõi đơn vẫn đang thống trị thị trường. Trên thực tế, nhà phát triển CPython có thể vẫn cảm thấy nóng khi nói đến đồng thời. May mắn thay, chúng tôi, những người mới học Python có thể nghỉ ngơi và tận hưởng thành quả của PEP 371, nơi mà n = 1006 đã chính thức được thêm vào các thư viện tiêu chuẩn vào năm 2008 và PEP 3156, nơi mà n = 1007 đã được đưa vào các thư viện tiêu chuẩn vào năm 2012. Trong phần đầu tiên của loạt bài về xử lý song song với Python, chúng ta sẽ xem xét đa luồng, cách triển khai nó với n = 1006 Show
Nguồn. Wikimedia Commons Chủ đề là một luồng thực thi riêng biệt. Khi bạn có một nhóm worker thread, chúng sẽ thực thi gần như đồng thời. Các luồng này sẽ chia sẻ một không gian dữ liệu chung, do đó, khái niệm Khóa thông dịch viên toàn cầu (GIL) rất quan trọng khi bạn cố gắng đa luồng tập lệnh python của mình. Những gì GIL làm là, trong ngắn hạn, một luồng Python chạy tại một thời điểm để tránh những thay đổi không nhất quán trong bộ nhớ dùng chung hoặc về lâu dài là tạo môi trường quản lý bộ nhớ an toàn cho luồng để đưa các thư viện C không an toàn cho luồng vào Python . Như vậy, các luồng sẽ khóa luồng gọi khi chúng cần sử dụng CPU để tính toán. Điều này làm cho các luồng kém hiệu quả hơn đối với các tác vụ liên quan đến CPU và hơn thế nữa đối với các tác vụ liên quan đến I/O, ví dụ:. g. kết nối mạng, phát hành các hoạt động cơ sở dữ liệu, v.v. Quy trình có thể được hiểu là một quy trình Python riêng biệt đã được rẽ nhánh từ quy trình mẹ và có trình thông dịch Python riêng. Do đó, mỗi quy trình sẽ có GIL riêng và sẽ không khóa các quy trình khác khi thực thi trên lõi CPU. Giá để tránh tắc nghẽn GIL là có chi phí bộ nhớ lớn hơn dưới dạng bản sao của không gian địa chỉ hoặc sao chép khi ghi nếu cần hỗ trợ cho mọi quy trình. Do đó, các quy trình thường được ưu tiên hơn khi thực hiện các tác vụ liên quan đến CPU e. g. thao tác ma trận Triển khai đa luồng của PythonThư viện tiêu chuẩn của Python, n = 1006 có giao diện cho luồng có sẵn qua %%timeit -n 30. Đối với các cựu chiến binh Python dày dạn kinh nghiệm, %%timeit -n 31 là thư viện ban đầu cho việc này. Giao diện này cung cấp các chức năng sau, nhưng mỗi phương thức có những hạn chế khác nhau về cách truyền đối số và không dễ dàng để chúng tôi theo dõi tiến trình
Trước khi chúng ta đi sâu vào các phương pháp này, hãy thảo luận về ưu và nhược điểm, trước tiên hãy thiết lập bối cảnh Khi chạy nó với %%timeit -n 35 ta được kết quả như sau n = 1000 Giả sử chúng ta muốn, vì lý do nào đó, chạy nó hàng trăm lần n = 100ÁP DỤNG & ÁP DỤNG_ASYNC Truyền một chức năng cho nhóm chủ đề. Điều này có hai biến thể. %%timeit -n 36 và %%timeit -n 37. Khi sử dụng phương thức %%timeit -n 38, bạn sẽ cần truyền một hàm có thể gọi được, cùng với một số đối số và/hoặc kwargs tùy chọn. Khi thực thi chức năng, nó sẽ chặn luồng gọi cho đến khi kết quả sẵn sàng hoặc một ngoại lệ đã được đưa ra. Do đó, %%timeit -n 39 thường được ưu tiên Khi sử dụng %%timeit -n 39, thay vì kết quả thực tế, nó sẽ trả về n = 10071, về cơ bản là lời hứa về kết quả mà bạn có thể nhận được bằng cách sử dụng hàm n = 10072. bạn cũng có thể chuyển vào một hàm n = 10073 và một hàm n = 10074 sẽ được thực thi khi luồng hoàn thành công việc và khi nó bị lỗi như nó luôn có trong mã của tôi ưu
Nhược điểm
ÁP DỤNG%%timeit -n 3 ÁP DỤNG + TQDMn = 1007 ÁP DỤNG_ASYNCn = 1004 ÁP DỤNG_ASYNC + TQDMn = 1005 APPLY_ASYNC + TQDM trong Gọi lạin = 1006MAP & MAP_ASYNC Tranh luận
trả lại
ưu
Một nhược điểm lớn đối với n = 10041 và n = 10075 là chúng ta sẽ cần thực thi lặp đi lặp lại n = 10043 hoặc biến thể không đồng bộ cho mỗi tập hợp đối số và/hoặc kwargs. Lặp lại không được tối ưu hóa hầu như luôn là cơn ác mộng khi nói đến khả năng mở rộng. Trong trường hợp này, n = 10044 là dreamcatcher của chúng ta. Tất cả những gì chúng ta cần làm là chuyển vào iterable và viola Cũng giống như n = 10041, n = 10078 có một biến thể không đồng bộ thường hoạt động tốt hơn vì n = 10078 sẽ chặn luồng gọi cho đến khi trả về kết quả Một đối số rất hữu ích khác là n = 10040, chấp nhận một số tự nhiên với giá trị mặc định là 1. Iterable của chúng ta sẽ được chia thành các phần, được gọi là tác vụ, có độ dài gần bằng độ dài của chunksize. Mỗi chuỗi sẽ là một nhiệm vụ mà họ cần phải hoàn thành trước khi yêu cầu một nhiệm vụ mới. Về bản chất, ________ 249 giúp bạn linh hoạt hơn trong việc lên lịch cho từng tác vụ, trong khi việc có ________ 250 mang lại cho bạn (nói chung) thông lượng tốt hơn và giảm số lần liên lạc giữa các luồng. Một nguyên tắc chung là có n = 10051 nếu bạn không biết mỗi nhiệm vụ sẽ mất bao lâu để hoàn thành (e. g. tối ưu hóa), và có n = 10052 nếu bạn đang mong đợi các tác vụ hoàn thành trong cùng một khoảng thời gian Nhược điểm
n = 10078 và n = 10079 cũng có một số nhược điểm. Một điều đặc biệt khó chịu là nó chỉ cho phép một đối số. Nếu chức năng của bạn chấp nhận nhiều đối số hoặc kwarg, đây là ba cách (nói chung) để đi bộ xung quanh nó 1. Chỉ cần làm cho nó xảy ra Không được khuyến khích; Bạn sẽ cần chỉ định mọi đối số ngay cả khi chúng là tùy chọn và cũng có thể cần phải bọc chức năng mục tiêu của bạn để biến điều đó thành hiện thực 2. Phương pháp một phần Chỉ khi đối số thay đổi là đối số đầu tiên được hàm chấp nhận 3. Không sử dụng n = 10061 hoặc n = 10062 Vâng, có những lựa chọn thay thế tốt hơn, như n = 10063 BẢN ĐỒ%%timeit -n 35 BẢN ĐỒ + TQDM%%timeit -n 36 MAP_ASYNC%%timeit -n 37IMAP & IMAP_UNORDERED Tranh luận
trả lại
ưu
%%timeit -n 352 được định nghĩa chính thức là phiên bản lười biếng hơn của n = 10078, có nghĩa là nó sẽ chuyển đầu vào có thể lặp lại của bạn thành một n = 10068 trước khi cắt nó thành các tác vụ, cũng như không đưa kết quả vào danh sách trước khi quay lại. Thay vào đó, nó sử dụng %%timeit -n 355 và %%timeit -n 356 để ủy thác nhiệm vụ. Không giống như n = 10078 sẽ trả về một danh sách kết quả hoặc n = 10079 trả về lời hứa về kết quả, %%timeit -n 352 và %%timeit -n 351 trả về kết quả ngay khi worker thread đưa ra kết quả. Do sự khác biệt này, kết quả không thể được đưa vào danh sách và thay vào đó sẽ cần nằm trong trình tạo, nơi người dùng có thể sử dụng %%timeit -n 361 để tìm nạp kết quả mới nhất. Điều này sẽ đặc biệt nếu chương trình của bạn không cần đợi tất cả các kết quả để bắt đầu bất kỳ xử lý hậu kỳ nào. Trên hết, nếu thứ tự thực hiện không quan trọng đối với bạn, thì về mặt lý thuyết, %%timeit -n 351 sẽ tốt hơn vì nó sẽ mang lại kết quả ngay sau khi thực thi được thực hiện bất kể thứ tự lặp lại của đầu vào (i. e. nếu bạn vượt qua %%timeit -n 363, bạn có thể nhận được kết quả là %%timeit -n 364, với thứ tự kết quả hoàn toàn được xác định bởi thời gian chạy) Cũng giống như n = 10078 và n = 10079, %%timeit -n 352 và biến thể của nó cũng có n = 10040, chấp nhận một số tự nhiên với giá trị mặc định là 1. Một nguyên tắc chung là có n = 10051 nếu bạn không biết mỗi nhiệm vụ sẽ mất bao lâu để hoàn thành (e. g. tối ưu hóa), và có n = 10052 nếu bạn đang mong đợi các tác vụ hoàn thành trong cùng một khoảng thời gian Nhược điểm
Tóm lại, không sử dụng %%timeit -n 374 và %%timeit -n 375 nếu bạn không thoải mái với trình tạo hoặc nếu bạn cần hoàn thành kết quả trước khi tiếp tục và không sử dụng %%timeit -n 375 nếu thứ tự quan trọng đối với bạn. Nếu bạn muốn chuyển trình tạo trở lại danh sách, hãy sử dụng n = 10078 và n = 10079 để thay thế Để giải quyết hạn chế của một đối số, vui lòng tham khảo n = 10078 và n = 10079 IMAPn = 1000 IMAP + TQDMn = 1001 IMAP_UNORDEREDn = 1002 IMAP_UNORDERED + TQDMn = 1003SƠ ĐỒ STAR & STARMAP_ASYNC Tranh luận
trả lại
ưu
n = 10063 và n = 10006 đã được giới thiệu trong Python 3. 3 để giải quyết chính xác vấn đề trong đó nhiều đối số không thể dễ dàng chuyển đến hàm đích. Thay vì truyền vào một iterable của arg, chúng ta sẽ cần truyền vào một iterable của iterable của args i. e. nếu chúng ta chuyển n = 10007 vào hàm n = 10008, nó sẽ thực thi n = 10009 và n = 10010. Vì vậy, hãy nhớ bọc các đối số của bạn thành một bộ (bộ nhớ không phát triển trên cây) ngay cả khi nó chỉ có một đối số (chúng tôi không phán xét). Đối với những trường hợp bạn sẽ có sự kết hợp giữa các đối số liên tục và các đối số khác nhau, nói chung có hai cách để xử lý vấn đề đó 1. Phương pháp từng phần Chỉ khi các đối số khác nhau là đối số đầu tiên được hàm chấp nhận 2. Nói lại Bằng cách xác định tất cả các đối số cho mỗi lệnh gọi hàm, điều này sẽ hoạt động đối với các đối số khác nhau ở các vị trí khác nhau Nhược điểm
STARMAPn = 1004 STARMAP_ASYNCn = 1005Bảng xếp hạng cuối cùng Từ bảng trên, chúng ta có thể thấy rằng khi được sử dụng đúng cách, đa luồng có thể tăng tốc tác vụ nặng I/O đơn giản của chúng ta. Những con số này thu được trên một phiên bản EC2 ở trạng thái không hoạt động, nghĩa là rất có thể nó sẽ khác với những gì bạn sẽ nhận được. Điều đó đang được nói, n = 10041 và n = 10075 đã liên tục vượt trội so với phần còn lại dựa trên kinh nghiệm và thử nghiệm của tôi, vì vậy nếu bạn muốn thử đa luồng, n = 10041 và n = 10075 sẽ là lựa chọn tốt nhất của bạnBạn cũng có thể thích… Logic có điều kiện hiệu quả trên Pandas DataFramesĐã đến lúc ngừng quá phụ thuộc vào. iterrows() và. áp dụng()hướng tới khoa học dữ liệu. com 7 cách dễ dàng để cải thiện quy trình làm việc khoa học dữ liệu của bạnNhững mẹo tôi đã học được khi làm việc với tư cách là Nhà khoa học dữ liệuhướng tới khoa học dữ liệu. com Thuật toán tìm kiếm gốc hiệu quả trong PythonTriển khai các thuật toán tìm kiếm hiệu quả để tìm gốc và tối ưu hóa trong Pythonhướng tới khoa học dữ liệu. com Trước khi bạn đi…Trong phần tiếp theo của loạt bài này, chúng ta sẽ xem xét lý do tại sao n = 1006 có thể không đủ tốt cho công việc hàng ngày của chúng ta và cũng sẽ xem qua một số giải pháp thay thế khác, hy vọng sẽ giúp bạn tăng tốc mã của mình. Hãy cho tôi biết nếu bạn đã học được điều gì mới từ điều này. Và xin vui lòng cho tôi biết nếu có những thủ thuật gọn gàng khác mà tôi đã bỏ lỡ |