Tài nguyên Python là gì?

PyOxidizer đã xác định định dạng dữ liệu tùy chỉnh để lưu trữ tài nguyên hữu ích cho việc thực thi trình thông dịch Python. Chúng tôi gọi định dạng dữ liệu này là tài nguyên đóng gói Python

Cách nó hoạt động là một số nhà sản xuất thu thập tài nguyên theo yêu cầu của trình thông dịch Python. Các tài nguyên này bao gồm nguồn mô-đun Python và mã byte, tệp dữ liệu/tài nguyên không phải mô-đun, mô-đun mở rộng và thư viện dùng chung. Siêu dữ liệu về các tài nguyên này và đôi khi chính dữ liệu tài nguyên thô được tuần tự hóa thành cấu trúc dữ liệu nhị phân

Vào thời gian chạy trình thông dịch Python, cấu trúc dữ liệu này được tải [nó có thể được nhúng trong tệp nhị phân hoặc tồn tại dưới dạng tệp độc lập] và được phân tích cú pháp. Trình tìm đường dẫn Meta Python tùy chỉnh [ OxidizedFinder từ oxidized_importer Python Extension] then uses the parsed data structure to power Python module importing.

Chức năng này tương tự như sử dụng tệp .zip để giữ các mô-đun Python. Tuy nhiên, cấu trúc dữ liệu tài nguyên đóng gói của Python tiên tiến hơn nhiều

Thực hiện¶

Việc triển khai chuẩn của trình ghi và trình phân tích cú pháp của cấu trúc dữ liệu này tồn tại trong thùng rỉ sét của python-packed-resources. Trang chủ chuẩn của thùng này là https. //github. com/indygreg/PyOxidizer/tree/main/python-packed-resources

thùng này được xuất bản để thùng. io tại https. // thùng. io/crates/python-packed-resources

Sự chỉ rõ¶

Từ mức cao, cấu trúc dữ liệu xác định một tài nguyên có thể lặp lại. Tài nguyên là một thực thể có tên, siêu dữ liệu và các trường blob. Thông thường, tài nguyên phổ biến nhất là mô-đun/gói Python. Nhưng các loại tài nguyên khác [chẳng hạn như thư viện dùng chung] được xác định

8 byte đầu tiên của cấu trúc dữ liệu là một tiêu đề ma thuật xác định nội dung là cấu trúc dữ liệu của chúng tôi và phiên bản của nó. 7 byte đầu tiên là pyembed và 1 byte sau biểu thị một phiên bản. Ngữ nghĩa của từng phiên bản được biểu thị trong các phần bên dưới

Bố cục cấp cao¶

Từ cấp độ cao, định dạng tuần tự hóa bao gồm

  • Một tiêu đề toàn cầu mô tả tải trọng tổng thể
  • Một chỉ mục mô tả các phần blob có trong tải trọng
  • Một chỉ mục mô tả từng tài nguyên và nội dung của nó
  • Một loạt các phần blob chứa dữ liệu được tham chiếu bởi chỉ mục tài nguyên

Một tài nguyên bao gồm nhiều trường khác nhau mô tả nó. Ví dụ về các trường bao gồm tên tài nguyên, mã nguồn và mã byte. Chỉ mục tài nguyên mô tả trường nào có mặt và tìm thấy chúng ở đâu trong tải trọng

Nội dung thực tế của các trường [e. g. byte thô chứa mã nguồn] được lưu trữ trong các phần dành riêng cho trường sau chỉ mục. Mỗi trường có phần riêng và dữ liệu cho tất cả các tài nguyên được lưu trữ cạnh nhau. e. g. bạn sẽ có tất cả dữ liệu cho tên tài nguyên theo sau là tất cả dữ liệu cho mã nguồn mô-đun

Định dạng dữ liệu cấp thấp được mô tả bên dưới. Tất cả các số nguyên là little-endian

13 byte đầu tiên sau tiêu đề ma thuật biểu thị tiêu đề chung. Tiêu đề toàn cầu bao gồm

  • Một u8 biểu thị số phần blob, blob_sections_count
  • Một u32 biểu thị độ dài của chỉ mục blob, blob_index_length
  • Một u32 biểu thị tổng số tài nguyên trong dữ liệu này, resources_count
  • Một u32 biểu thị độ dài của chỉ mục tài nguyên, python-packed-resources0

Theo sau tiêu đề toàn cầu là chỉ mục blob. Chỉ mục blob mô tả các phần blob khác nhau có trong tải trọng sau chỉ mục tài nguyên

Mỗi mục trong chỉ mục blob bao gồm một tập hợp các trường xác định siêu dữ liệu về từng phần blob một cách hợp lý. Điều này được mã hóa bằng điểm đánh dấu bắt đầu mục nhập u8, theo sau là giá trị loại trường N u8 và siêu dữ liệu tương ứng của chúng, theo sau là điểm đánh dấu kết thúc mục nhập u8. Chỉ mục blob được chấm dứt bởi điểm đánh dấu cuối chỉ mục u8. Tổng số byte trong chỉ mục blob bao gồm cả điểm đánh dấu cuối chỉ mục phải là blob_index_length

Theo sau chỉ mục blob là chỉ mục tài nguyên. Mỗi mục nhập trong chỉ mục này xác định một tập hợp siêu dữ liệu thưa thớt mô tả một tài nguyên. Các mục bao gồm một loạt u8 phần siêu dữ liệu xác định, theo sau là các mô tả bổ sung theo lĩnh vực cụ thể. Ví dụ: giá trị của python-packed-resources7 biểu thị độ dài của tên tài nguyên và ngay sau đó là giá trị python-packed-resources8 giữ độ dài nói trên. Xem phần bên dưới để biết từng trường được chỉ mục này theo dõi

Theo sau chỉ mục tài nguyên là dữ liệu blob. Dữ liệu blob bao gồm một cách hợp lý các phần khác nhau chứa dữ liệu cho các trường khác nhau cho các tài nguyên khác nhau. Nhưng không có cấu trúc bên trong hoặc dải phân cách. tất cả các đốm màu riêng lẻ được đặt cạnh nhau

Các loại trường đốm màu¶

Chỉ mục Blob cho phép phân bổ một tập hợp siêu dữ liệu thưa thớt với mỗi mục nhập phần blob. Loại siêu dữ liệu được chuyển tải được xác định bởi một u8. Một số loại trường có siêu dữ liệu bổ sung sau trường đó

Các loại trường khác nhau và ngữ nghĩa của chúng tuân theo

pyembed0Kết thúc chỉ mục. Trường này chỉ ra rằng không còn mục nhập chỉ mục blob nào nữa và chúng tôi đã đạt đến cuối chỉ mục blob. pyembed1Bắt đầu mục blob. Gặp phải giá trị này báo hiệu sự bắt đầu của một phần blob mới. Từ quan điểm đặc điểm kỹ thuật, điều này không bắt buộc. Nhưng nó giúp đảm bảo trạng thái trình phân tích cú pháp. pyembed2Mục nhập phần cuối của đốm màu. Gặp phải giá trị này báo hiệu sự kết thúc của định nghĩa phần blob hiện tại. u8 gặp phải tiếp theo trong chỉ mục phải là pyembed1 để biểu thị một mục mới hoặc pyembed0 để biểu thị kết thúc chỉ mục. python-packed-resources7Loại trường tài nguyên. Trường này xác định trường tài nguyên nào mà phần blob này đang giữ dữ liệu cho. Một u8 theo sau cái này sẽ chứa giá trị loại trường tài nguyên [xem phần bên dưới]. pyembed8Chiều dài tải trọng thô. Trường này xác định độ dài thô tính bằng byte của phần blob trong tải trọng. pyembed9 chứa độ dài đó sẽ ngay lập tức theo sau u8 này. u81

Cơ chế đệm bên trong. Trường này xác định phần đệm bên trong giữa các phần tử trong phần blob. Theo sau u8 này là một u8 khác biểu thị cơ chế đệm

pyembed1 biểu thị không có phần đệm. python-packed-resources7 biểu thị phần đệm NULL [một pyembed0 giữa các phần tử]

Nếu không có, không có phần đệm nào được giả định. Nếu dữ liệu tải trọng bao gồm một cách hợp lý các tài nguyên rời rạc [e. g. tệp tài nguyên gói Python], thì phần đệm cũng áp dụng cho các phần tử phụ này

Các loại trường tài nguyên¶

Chỉ mục tài nguyên cho phép phân bổ một tập hợp siêu dữ liệu thưa thớt với mọi tài nguyên. Một u8 cho biết siêu dữ liệu nào đang được chuyển tải. Một số loại trường có siêu dữ liệu bổ sung theo sau u88 này xác định thêm trường. Các giá trị của từng loại siêu dữ liệu được xác định tuân theo

pyembed0Kết thúc chỉ mục. Loại đặc biệt để biểu thị phần cuối của một chỉ mục. pyembed1Bắt đầu nhập tài nguyên. Báo hiệu sự khởi đầu của một tài nguyên mới. Từ quan điểm đặc điểm kỹ thuật, điều này không bắt buộc. Nhưng nó giúp đảm bảo trạng thái trình phân tích cú pháp. python-packed-resources7

Hương vị tài nguyên. Khai báo loại tài nguyên mà mục nhập này đại diện. Một u8 xác định hương vị tài nguyên ngay sau byte này. Xem phần bên dưới để biết các hương vị tài nguyên hợp lệ

Trường này không được dùng trong phiên bản 2 để thay thế cho các trường riêng lẻ thể hiện sự hiện diện của một loại tài nguyên. [Xem các trường bắt đầu từ blob_sections_count3. ]

pyembed2Kết thúc mục nhập tài nguyên. u8 gặp phải tiếp theo trong chỉ mục phải là điểm cuối của chỉ mục hoặc điểm bắt đầu của điểm đánh dấu tài nguyên. pyembed8Tên tài nguyên. Một python-packed-resources8 biểu thị độ dài tính bằng byte của tên tài nguyên ngay sau byte này. Tên tài nguyên phải là UTF-8 hợp lệ. u81Cờ gói hàng. Nếu gặp phải, tài nguyên được xác định là gói Python. blob_sections_count9Cờ gói không gian tên. Nếu gặp phải, tài nguyên được xác định là gói không gian tên Python. u320Mã nguồn mô-đun Python trong bộ nhớ. Một u32 biểu thị độ dài tính bằng byte của mã nguồn của mô-đun ngay sau byte này. u322Mã byte mô-đun Python trong bộ nhớ. Một u32 biểu thị độ dài tính bằng byte của mã byte của mô-đun ngay sau byte này. u324Mô-đun Python trong bộ nhớ được tối ưu hóa mã byte cấp 1. Một u32 biểu thị độ dài tính bằng byte của mã byte cấp 1 tối ưu hóa của mô-đun ngay sau byte này. u326Mô-đun Python trong bộ nhớ được tối ưu hóa mã byte cấp 2. Tương tự như trước, ngoại trừ tối ưu hóa mã byte cấp 2. u327Thư viện chia sẻ mô-đun mở rộng Python trong bộ nhớ. Một u32 biểu thị độ dài tính bằng byte của mã máy của mô-đun mở rộng ngay sau byte này. u329Dữ liệu tài nguyên Python trong bộ nhớ. Nếu gặp phải, mô-đun/gói chứa tệp tài nguyên không phải mô-đun và số lượng tài nguyên được chứa trong u32 ngay sau đó. Theo sau u32 này là một mảng blob_index_length2 biểu thị tên tài nguyên và kích thước tải trọng cho từng tài nguyên trong gói này. blob_index_length3Tài nguyên phân phối Python trong bộ nhớ. Xác định tài nguyên được truy cập từ blob_index_length4 API. Nếu gặp phải, mô-đun/gói chứa siêu dữ liệu phân phối mô tả gói. Số lượng tệp được mô tả được chứa trong một u32 ngay sau byte này. Theo sau u32 này là một mảng blob_index_length2 biểu thị tên tệp phân phối và kích thước tải trọng cho từng tệp ảo trong bản phân phối này. blob_index_length8Thư viện chia sẻ trong bộ nhớ. Nếu được đặt, tài nguyên này là thư viện dùng chung chứ không phải mô-đun Python. Trường tên tài nguyên là tên của thư viện được chia sẻ này, với phần mở rộng tệp [vì nó sẽ xuất hiện trong siêu dữ liệu của trình tải nhị phân động để biểu thị sự phụ thuộc của thư viện]. Một pyembed9 biểu thị độ dài tính bằng byte của dữ liệu thư viện dùng chung theo sau. Thư viện dùng chung này phải được tải từ bộ nhớ. u320Tên phụ thuộc thư viện được chia sẻ. Trường này cho biết tên của các thư viện dùng chung mà thực thể này phụ thuộc vào. Số lượng tên thư viện được chứa trong một python-packed-resources8 ngay sau byte này. Theo sau python-packed-resources8 này là một mảng python-packed-resources8 biểu thị độ dài của tên thư viện cho mỗi phụ thuộc thư viện dùng chung. Mỗi phụ thuộc thư viện dùng chung được mô tả có thể được mô tả hoặc không được mô tả bởi các mục nhập khác trong cấu trúc dữ liệu này. u324Đường dẫn hệ thống tệp tương đối đến mã nguồn mô-đun Python. Một u32 giữ độ dài tính bằng byte của đường dẫn hệ thống tệp được mã hóa trong mã hóa đường dẫn tệp gốc nền tảng theo sau. Mã nguồn của mô-đun Python sẽ được đọc từ một tệp tại đường dẫn này. u326Đường dẫn hệ thống tệp tương đối đến mã byte mô-đun Python. Tương tự như phần trước ngoại trừ đường dẫn hệ thống tệp chứa mã byte của mô-đun Python. u327Đường dẫn hệ thống tệp tương đối đến mã byte mô-đun Python ở mức tối ưu hóa 1. Tương tự như trước đó ngoại trừ những gì đang được trỏ đến. u328Đường dẫn hệ thống tệp tương đối đến mã byte mô-đun Python ở mức tối ưu hóa 2. Tương tự như trước đó ngoại trừ những gì đang được trỏ đến. u329Đường dẫn hệ thống tệp tương đối đến thư viện chia sẻ mô-đun mở rộng Python. Tương tự như phần trước ngoại trừ tệp chứa mô-đun mở rộng Python có thể tải dưới dạng thư viện dùng chung. resources_count0Đường dẫn hệ thống tệp tương đối đến tài nguyên gói Python. Số lượng tài nguyên được chứa trong một u32 ngay sau đó. Theo sau u32 này là một mảng resources_count3 biểu thị tên tài nguyên và đường dẫn hệ thống tệp tới từng tài nguyên trong gói này. resources_count4

Đường dẫn hệ thống tệp tương đối đến tài nguyên phân phối Python

Xác định tài nguyên được truy cập từ blob_index_length4 API. Nếu gặp phải, mô-đun/gói chứa siêu dữ liệu phân phối mô tả gói. Số lượng tệp được mô tả được chứa trong một u32 ngay sau byte này. Theo sau u32 này là một mảng resources_count3 biểu thị tên tệp phân phối và đường dẫn hệ thống tệp đến tệp phân phối đó

blob_sections_count3Là cờ mô-đun Python. Nếu được đặt, tài nguyên này chứa dữ liệu cho gói hoặc mô-đun Python có thể nhập. Dữ liệu tài nguyên được liên kết với các gói Python và thuộc loại này. Cờ mô-đun mở rộng dựng sẵn u320Is. Loại này đại diện cho một mô-đun mở rộng Python được tích hợp sẵn [được biên dịch thành] chính trình thông dịch hoặc được cung cấp cho trình thông dịch thông qua u321 sao cho nó phải được nhập bằng trình nhập nội trang. u322Cờ mô-đun Python bị đóng băng. Loại này đại diện cho một mô-đun Python có mã byte bị đóng băng và được cung cấp cho trình thông dịch Python thông qua mảng u323 và phải được nhập bằng trình nhập bị đóng băng. u324Là cờ mở rộng Python. Loại này đại diện cho một phần mở rộng Python đã biên dịch. Các tiện ích mở rộng có các yêu cầu cụ thể về cách chúng được tải và được phân biệt với các mô-đun Python thông thường. u325Là cờ thư viện dùng chung. Loại này đại diện cho một thư viện dùng chung có thể được tải vào một quy trình. u326Là cờ dữ liệu tên tệp utf-8. Loại này đại diện cho một tên tệp tùy ý. Tên tài nguyên là tên tệp được mã hóa UTF-8 của tệp mà tài nguyên này đại diện. Dữ liệu của tệp được nhúng trong bộ nhớ hoặc được tham chiếu qua tham chiếu đường dẫn tương đối. u327

Dữ liệu tệp là cờ thực thi

Nếu được đặt, tệp tùy ý mà tài nguyên này theo dõi sẽ được đánh dấu là có thể thực thi được

u328

Dữ liệu tệp nhúng

Nếu có, tài nguyên phải là tài nguyên tệp và trường này chứa dữ liệu tệp thô của nó trong bộ nhớ

Một pyembed9 chứa độ dài của dữ liệu được nhúng theo sau trường này

python-packed-resources00

Dữ liệu tệp đường dẫn tương đối UTF-8

Nếu có, tài nguyên phải là tài nguyên tệp và trường này xác định đường dẫn tương đối chứa dữ liệu của tệp đó. Tên tệp đường dẫn tương đối được mã hóa UTF-8

Một u32 biểu thị độ dài của đường dẫn tương đối UTF-8 [tính bằng byte] theo sau

Hương vị tài nguyên¶

Quan trọng

Các hương vị tài nguyên được liệt kê không được dùng nữa sau phiên bản 1. Thay vào đó, bạn nên sử dụng các trường riêng lẻ để thể hiện danh tính tài nguyên

Định dạng dữ liệu cho phép xác định các loại/hương vị khác nhau của tài nguyên. Hương vị này của tài nguyên được xác định bởi một u8. Các hương vị được công bố là

pyembed0Không có hương vị. không nên gặp. pyembed1Mô-đun/gói Python. Điều này tương đương với trường tài nguyên blob_sections_count3 được đặt. python-packed-resources7Mô-đun mở rộng Python tích hợp. Điều này tương đương với trường tài nguyên u320 được đặt. pyembed8Mô-đun Python đông lạnh. Điều này tương đương với trường tài nguyên u322 được đặt. u81Phần mở rộng Python. Điều này tương đương với trường tài nguyên u324 được đặt. blob_sections_count9Thư viện chia sẻ. Điều này tương đương với trường tài nguyên u325 được đặt

Định dạng python-packed-resources14¶

Định dạng dữ liệu tài nguyên đóng gói được phát hành/chính thức hóa ban đầu

Hỗ trợ các loại trường tài nguyên lên đến và bao gồm resources_count4

Định dạng python-packed-resources16¶

Phiên bản 2 của định dạng dữ liệu tài nguyên đóng gói

Phiên bản này giới thiệu các giá trị loại trường blob_sections_count3 đến u325. Loại trường hương vị tài nguyên [python-packed-resources7] không được dùng nữa và thay vào đó nên sử dụng các loại trường riêng lẻ biểu thị các loại tài nguyên

[PyOxidizer đã loại bỏ mã thời gian chạy khi xem loại trường python-packed-resources7 khi định dạng này được giới thiệu. ]

Định dạng python-packed-resources21¶

Phiên bản 3 của định dạng dữ liệu tài nguyên đóng gói

Phiên bản này giới thiệu các giá trị loại trường u326 đến python-packed-resources00

Các trường này cung cấp khả năng cho tài nguyên tự xác định chính nó dưới dạng tên tệp tùy ý và cho dữ liệu tệp tùy ý được nhúng trong cấu trúc dữ liệu hoặc được tham chiếu qua đường dẫn tương đối

Không giống như các trường trước sử dụng mã hóa gốc hệ điều hành của đường dẫn hệ thống tệp [u88 trên POSIX và python-packed-resources25 trên Windows], đường dẫn cho các trường mới này sử dụng UTF-8. Điều này không thể đại diện cho tất cả các đường dẫn hợp lệ trên tất cả các nền tảng. Nhưng nó có thể di động và hoạt động cho hầu hết các con đường gặp phải trong tự nhiên

Cân nhắc thiết kế¶

Thiết kế của định dạng dữ liệu tài nguyên đóng gói bị ảnh hưởng bởi một số cân nhắc

Hiệu suất là một cân nhắc quan trọng. Chúng tôi muốn mọi thứ diễn ra nhanh nhất có thể. Các kích thước có thể ảnh hưởng đến hiệu suất bao gồm thời gian phân tích cú pháp, kích thước tải trọng và các mẫu truy cập I/O

Tải trọng được thiết kế sao cho dữ liệu chỉ mục ở đầu để người đọc chỉ phải đọc một lát dữ liệu liền kề để hiểu đầy đủ dữ liệu bên trong. Điều này trái ngược với việc nhảy xung quanh toàn bộ cấu trúc dữ liệu để trích xuất siêu dữ liệu của dữ liệu bên trong. Điều này có nghĩa là chúng tôi chỉ cần trang trong một phần nhỏ của toàn bộ cấu trúc dữ liệu sao lưu để khởi tạo trình nhập tùy chỉnh của chúng tôi. Ngoài ra, dữ liệu chỉ mục được đọc tuần tự. I/O tuần tự phải luôn nhanh hơn I/O truy cập ngẫu nhiên

x86 là endian nhỏ, vì vậy chúng tôi sử dụng số nguyên endian nhỏ để chúng tôi không cần lãng phí các chu kỳ khi chuyển đổi endian

Chúng tôi lưu trữ tất cả dữ liệu cho cùng một trường cạnh nhau trong cấu trúc dữ liệu. Điều này trái ngược với việc nói đóng gói tất cả dữ liệu của tài nguyên A sau đó là tài nguyên B, v.v. Chúng tôi làm điều này để giúp tối đa hóa vị trí cho dữ liệu tương tự. Điều này có thể giúp cải thiện hiệu suất vì thường cùng một trường cho nhiều tài nguyên được truy cập cùng nhau. e. g. một nhà nhập khẩu sẽ truy cập vào một loạt các mục nhập mã byte của mô-đun cùng một lúc. Địa phương này giúp giảm thiểu số lượng trang phải đọc. Địa phương cũng có thể giúp mang lại tỷ lệ nén cao hơn

Mọi thứ được thiết kế để tạo điều kiện cho người đọc tận dụng 0 bản sao. Nếu một đầu đọc có cấu trúc dữ liệu trong bộ nhớ, chúng tôi không muốn yêu cầu nó sao chép bộ nhớ để tham chiếu các mục nhập. Trong Rust speak, chúng tôi sẽ có thể lưu giữ tài liệu tham khảo python-packed-resources26 ở mọi nơi

Không có tổng kiểm tra dữ liệu vì chúng tôi không muốn phát sinh chi phí I/O để đọc toàn bộ đốm màu. Nó có thể được thêm vào như một tính năng tùy chọn

Các tính năng tiềm năng trong tương lai¶

Cấu trúc dữ liệu này đủ mạnh để PyOxidizer sử dụng để cấp nguồn cho việc nhập mọi mô-đun Python được trình thông dịch Python sử dụng. Tuy nhiên, có nhiều khía cạnh khác nhau có thể được cải thiện

Nén¶

Một lĩnh vực tiềm năng để tối ưu hóa là sử dụng nén chung. Các trường khác nhau sẽ nén tốt - ở chế độ phát trực tuyến hoặc bằng cách sử dụng từ điển nén. Tất nhiên, quá trình nén sẽ làm suy yếu bản sao 0. Nhưng trong những môi trường mà chúng tôi muốn tối ưu hóa kích thước, điều đó có thể là mong muốn

Tính di động của nền tảng¶

Hiện tại, các đường dẫn hệ thống tệp được mã hóa dưới dạng nền tảng gốc. Điều đó có nghĩa là u88 trên POSIX và python-packed-resources25 trên Windows. Đây không phải là xách tay

Hầu hết các tên tệp có khả năng an toàn ASCII hoặc UTF-8. Đối với trường hợp phổ biến khi chúng tôi không cần tên tệp gốc nền tảng để duy trì sự khác biệt về mã hóa tinh tế, chúng tôi có thể biểu thị đường dẫn dưới dạng một loại chuỗi đơn giản hơn

Tài nguyên trong Python là gì?

Hàm này trả về một đối tượng mô tả các tài nguyên được sử dụng bởi quy trình hiện tại hoặc các phần tử con của nó, như được chỉ định bởi tham số who . Tham số who phải được chỉ định bằng cách sử dụng một trong các hằng số RUSAGE_* được mô tả bên dưới.

Làm cách nào để sử dụng mô-đun tài nguyên python?

Sử dụng mô-đun tài nguyên trong Python .
1. 0 Thiết lập hệ sinh thái. Trước khi chúng tôi bắt đầu làm việc với chức năng được cung cấp cho chúng tôi bởi mô-đun tài nguyên, trước tiên chúng tôi cần nhập mô-đun. .
1. 1 Cách sử dụng tham số cơ bản. .
1. 2 trình diễn. .
1. 3 Tiến về phía trước

Đầu bếp Python là gì?

Chef là công cụ quản lý cấu hình tuyệt vời , được sử dụng rộng rãi trong nhiều ngành. Nếu bạn chưa quen với cách điều hành chef/chef-solo, vui lòng xem qua bài viết này trước. Một trong những tính năng hay nhất của Chef là bộ sưu tập tài nguyên. Tài nguyên cho phép Chef xử lý cấu hình của máy chủ được chỉ định.

Chủ Đề