Cơ chế lên lịch
Quá trình xử lý dữ liệu trong biểu đồ MediaPipe diễn ra bên trong các nút xử lý được xác định là lớp con CalculatorBase
. Hệ thống lập lịch sẽ quyết định thời điểm chạy mỗi phép tính.
Mỗi biểu đồ có ít nhất một hàng đợi trình lập lịch. Mỗi hàng đợi trình lập lịch biểu có chính xác một executor. Các nút được gán tĩnh cho hàng đợi (và do đó cho trình thực thi). Theo mặc định, có một hàng đợi, trong đó trình thực thi là một nhóm luồng với một số luồng dựa trên khả năng của hệ thống.
Mỗi nút có một trạng thái lập lịch biểu, có thể là chưa sẵn sàng, sẵn sàng hoặc đang chạy. Hàm sẵn sàng xác định liệu một nút đã sẵn sàng chạy hay chưa. Hàm này được gọi khi khởi chạy biểu đồ, bất cứ khi nào một nút chạy xong và bất cứ khi nào trạng thái đầu vào của nút thay đổi.
Hàm sẵn sàng được dùng sẽ phụ thuộc vào loại nút. Một nút không có dữ liệu đầu vào của luồng được gọi là nút nguồn; các nút nguồn luôn sẵn sàng chạy, cho đến khi các nút đó cho khung biết rằng chúng không còn dữ liệu nào để đầu ra và tại thời điểm đó chúng sẽ bị đóng.
Các nút không phải nguồn đã sẵn sàng nếu chúng có đầu vào để xử lý và nếu các đầu vào đó tạo thành một nhóm đầu vào hợp lệ theo các điều kiện do chính sách đầu vào của nút đặt ra (thảo luận bên dưới). Hầu hết các nút đều sử dụng chính sách nhập mặc định, nhưng một số nút chỉ định một chính sách khác.
Khi một nút đã sẵn sàng, một tác vụ sẽ được thêm vào hàng đợi trình lập lịch biểu tương ứng. Đây là hàng đợi ưu tiên. Hàm ưu tiên hiện đã được khắc phục và có tính đến các thuộc tính tĩnh của các nút cũng như cách sắp xếp cấu trúc liên kết của các nút trong biểu đồ. Ví dụ: các nút gần cạnh đầu ra của biểu đồ có mức độ ưu tiên cao hơn, trong khi các nút nguồn có mức độ ưu tiên thấp nhất.
Mỗi hàng đợi được phân phát bởi một trình thực thi, chịu trách nhiệm thực sự chạy tác vụ bằng cách gọi mã của máy tính. Bạn có thể cung cấp và định cấu hình các executor khác nhau; bạn có thể dùng để tuỳ chỉnh việc sử dụng tài nguyên thực thi (ví dụ: bằng cách chạy một số nút trên các luồng có mức độ ưu tiên thấp hơn).
Đồng bộ hoá dấu thời gian
Quá trình thực thi biểu đồ MediaPipe được phi tập trung: không có đồng hồ chung và các nút khác nhau có thể xử lý dữ liệu từ nhiều dấu thời gian cùng một lúc. Nhờ vậy, công suất tạo ra sẽ cao hơn thông qua đường ống.
Tuy nhiên, thông tin về thời gian rất quan trọng đối với nhiều quy trình làm việc liên quan đến nhận thức. Các nút nhận nhiều luồng đầu vào thường cần phải điều phối chúng theo một cách nào đó. Ví dụ: trình phát hiện đối tượng có thể xuất danh sách các hình chữ nhật ranh giới từ một khung, và thông tin này có thể được đưa vào một nút kết xuất. Nút này sẽ xử lý thông tin này cùng với khung gốc.
Do đó, một trong những nhiệm vụ chính của khung MediaPipe là cung cấp tính năng đồng bộ hoá đầu vào cho các nút. Về cơ chế khung, vai trò chính của dấu thời gian là đóng vai trò như một khoá đồng bộ hoá.
Hơn nữa, MediaPipe được thiết kế để hỗ trợ các phép toán tất định, điều này rất quan trọng trong nhiều trường hợp (kiểm thử, mô phỏng, xử lý hàng loạt, v.v.), đồng thời cho phép tác giả biểu đồ nới lỏng thuật toán tất định khi cần thiết để đáp ứng các hạn chế theo thời gian thực.
Hai mục tiêu của tính năng đồng bộ hoá và thuật toán tất định là nền tảng của nhiều lựa chọn thiết kế. Đáng chú ý, các gói được đẩy vào một luồng nhất định phải có dấu thời gian tăng đơn điệu: đây không chỉ là giả định hữu ích cho nhiều nút mà còn được logic đồng bộ hoá dựa vào. Mỗi luồng có một giới hạn dấu thời gian, đây là dấu thời gian thấp nhất có thể được cho phép đối với một gói mới trên luồng. Khi một gói có dấu thời gian T
đến, đường liên kết sẽ tự động chuyển đến T+1
để phản ánh yêu cầu về đơn điệu. Điều này cho phép khung biết chắc chắn rằng sẽ không còn gói tin nào có dấu thời gian thấp hơn T
đến.
Chính sách nhập
Quá trình đồng bộ hoá được xử lý cục bộ trên từng nút, sử dụng chính sách đầu vào do nút chỉ định.
Chính sách đầu vào mặc định (do DefaultInputStreamHandler
xác định) cung cấp tính năng đồng bộ hoá xác định các dữ liệu đầu vào với những đảm bảo sau:
Nếu các gói có cùng dấu thời gian được cung cấp trên nhiều luồng đầu vào, thì các gói này sẽ luôn được xử lý cùng nhau bất kể thứ tự đến theo thời gian thực.
Các nhóm dữ liệu đầu vào được xử lý theo thứ tự dấu thời gian tăng dần.
Không có gói nào bị bỏ qua và quá trình xử lý hoàn toàn xác định.
Nút này sẽ sẵn sàng xử lý dữ liệu ngay khi có thể dựa trên các điều kiện đảm bảo ở trên.
Để giải thích cách hoạt động của tính năng này, chúng tôi cần đưa ra định nghĩa về dấu thời gian cố định. Chúng ta nói dấu thời gian trong luồng được giải quyết nếu dấu thời gian thấp hơn giới hạn dấu thời gian. Nói cách khác, dấu thời gian được xác định cho một luồng sau khi xác định được trạng thái đầu vào tại dấu thời gian đó là không thể thu hồi: có một gói hoặc chắc chắn rằng một gói có dấu thời gian đó sẽ không đến.
Dấu thời gian được quyết định trên nhiều luồng nếu dấu thời gian được đặt trên từng luồng đó. Hơn nữa, nếu một dấu thời gian được giải quyết, thì điều đó có nghĩa là tất cả các dấu thời gian trước đó cũng được giải quyết. Do đó, dấu thời gian đã giải quyết có thể được xử lý xác định theo thứ tự tăng dần.
Theo định nghĩa này, một máy tính có chính sách nhập mặc định sẽ sẵn sàng nếu có một dấu thời gian được quyết định trên tất cả các luồng đầu vào và chứa một gói trên ít nhất một luồng đầu vào. Chính sách đầu vào cung cấp tất cả các gói có sẵn cho dấu thời gian quyết định dưới dạng một nhóm đầu vào duy nhất cho công cụ tính.
Một hệ quả của hành vi xác định này là đối với các nút có nhiều luồng đầu vào, về mặt lý thuyết, các nút có thể chờ một dấu thời gian không bị ràng buộc và một số lượng gói không giới hạn có thể được lưu vào vùng đệm trong thời gian chờ đợi. (Xem xét một nút có hai luồng đầu vào, một trong số đó tiếp tục gửi các gói trong khi nút còn lại không gửi gì và không chuyển tiếp liên kết.)
Do đó, chúng tôi cũng cung cấp các chính sách đầu vào tuỳ chỉnh: chẳng hạn như phân tách dữ liệu đầu vào trong các tập hợp đồng bộ hoá khác nhau do SyncSetInputStreamHandler
xác định hoặc tránh đồng bộ hoá hoàn toàn và xử lý dữ liệu đầu vào ngay khi chúng được ImmediateInputStreamHandler
xác định.
Điều khiển luồng
Có hai cơ chế kiểm soát luồng chính. Cơ chế backpressure sẽ điều tiết quá trình thực thi các nút ngược dòng (upstream) khi các gói được lưu vào vùng đệm trên luồng đạt đến giới hạn (có thể định cấu hình) do CalculatorGraphConfig::max_queue_size
xác định. Cơ chế này duy trì hành vi tất định và bao gồm một hệ thống tránh tắc nghẽn giúp nới lỏng các giới hạn đã định cấu hình khi cần.
Hệ thống thứ hai bao gồm chèn các nút đặc biệt có thể thả gói theo giới hạn theo thời gian thực (thường sử dụng chính sách đầu vào tuỳ chỉnh) do FlowLimiterCalculator
xác định. Ví dụ: một mẫu phổ biến sẽ đặt nút điều khiển luồng ở đầu vào của biểu đồ con, có kết nối vòng lặp từ đầu ra cuối cùng đến nút kiểm soát luồng. Do đó, nút điều khiển luồng có thể theo dõi số lượng dấu thời gian đang được xử lý trong biểu đồ hạ nguồn và bỏ gói nếu số lượng này đạt đến giới hạn (có thể định cấu hình). Đồng thời, vì các gói được bỏ lên luồng lên trên, chúng tôi tránh được những công việc lãng phí phát sinh từ việc xử lý một phần dấu thời gian, sau đó bỏ gói giữa các giai đoạn trung gian.
Phương pháp tính toán này cho phép tác giả biểu đồ kiểm soát vị trí có thể bỏ gói dữ liệu, đồng thời cho phép linh hoạt điều chỉnh và tuỳ chỉnh hành vi của biểu đồ tuỳ thuộc vào các hạn chế về tài nguyên.