مکانیک برنامه ریزی
پردازش داده ها در یک نمودار MediaPipe در داخل گره های پردازشی که به عنوان زیر کلاس های CalculatorBase
تعریف شده اند، انجام می شود. سیستم زمان بندی تصمیم می گیرد که هر ماشین حساب چه زمانی باید اجرا شود.
هر نمودار حداقل یک صف زمانبندی دارد. هر صف زمانبندی دقیقاً یک مجری دارد. گره ها به صورت ایستا به یک صف (و در نتیجه به یک مجری) اختصاص داده می شوند. به طور پیش فرض یک صف وجود دارد که مجری آن یک Thread Pool با تعدادی Thread بر اساس قابلیت های سیستم است.
هر گره دارای یک حالت زمان بندی است که می تواند آماده ، آماده یا در حال اجرا نباشد. یک تابع آمادگی تعیین می کند که آیا یک گره آماده اجرا است یا خیر. این تابع در زمان اولیه سازی گراف، هر زمان که یک گره کار خود را تمام می کند، و هر زمان که وضعیت ورودی های یک گره تغییر می کند، فراخوانی می شود.
تابع آمادگی مورد استفاده بستگی به نوع گره دارد. یک گره بدون ورودی جریان به عنوان گره منبع شناخته می شود. گره های منبع همیشه آماده اجرا هستند، تا زمانی که به فریم ورک بگویند که داده دیگری برای خروجی ندارند، در این مرحله بسته می شوند.
گرههای غیر منبع آماده هستند اگر ورودیهایی برای پردازش داشته باشند، و اگر آن ورودیها یک مجموعه ورودی معتبر را با توجه به شرایط تعیینشده توسط خطمشی ورودی گره تشکیل دهند (در زیر بحث میشود). بیشتر گرهها از سیاست ورودی پیشفرض استفاده میکنند، اما برخی از گرهها سیاست دیگری را مشخص میکنند.
هنگامی که یک گره آماده می شود، یک کار به صف زمانبندی مربوطه اضافه می شود که یک صف اولویت است. تابع اولویت در حال حاضر ثابت است و ویژگیهای ایستا گرهها و مرتبسازی توپولوژیکی آنها را در نمودار در نظر میگیرد. به عنوان مثال، گره های نزدیک به سمت خروجی نمودار دارای اولویت بالاتر هستند، در حالی که گره های منبع کمترین اولویت را دارند.
هر صف توسط یک مجری ارائه می شود که وظیفه اجرای واقعی کار را با فراخوانی کد ماشین حساب بر عهده دارد. مجری های مختلف را می توان تهیه و پیکربندی کرد. این را می توان برای سفارشی کردن استفاده از منابع اجرا، به عنوان مثال با اجرای گره های خاص بر روی رشته های با اولویت پایین تر استفاده کرد.
همگام سازی مهر زمانی
اجرای گراف MediaPipe غیرمتمرکز است: ساعت جهانی وجود ندارد و گرههای مختلف میتوانند دادههای مُهرهای زمانی مختلف را همزمان پردازش کنند. این اجازه می دهد تا توان عملیاتی بالاتر از طریق خط لوله.
با این حال، اطلاعات زمان برای بسیاری از گردشهای کاری ادراک بسیار مهم است. گره هایی که جریان های ورودی متعددی را دریافت می کنند، عموماً باید آنها را به نحوی هماهنگ کنند. به عنوان مثال، یک آشکارساز شی ممکن است فهرستی از مستطیل های مرزی را از یک قاب خروجی دهد، و این اطلاعات ممکن است به یک گره رندر داده شود، که باید آن را همراه با فریم اصلی پردازش کند.
بنابراین، یکی از مسئولیت های کلیدی چارچوب MediaPipe، ارائه همگام سازی ورودی برای گره ها است. از نظر مکانیک چارچوب، نقش اصلی مهر زمانی این است که به عنوان یک کلید همگام سازی عمل کند.
علاوه بر این، MediaPipe برای پشتیبانی از عملیات قطعی طراحی شده است، که در بسیاری از سناریوها مهم است (تست، شبیهسازی، پردازش دستهای و غیره)، در حالی که به نویسندگان گراف اجازه میدهد تا جبرگرایی را در جایی که برای برآوردن محدودیتهای بلادرنگ نیاز دارند، کاهش دهند.
دو هدف همگام سازی و جبرگرایی زیربنای چندین انتخاب طراحی هستند. نکته قابل توجه، بستههایی که به یک جریان داده میشوند باید دارای مُهرهای زمانی افزایشی یکنواخت باشند: این فقط یک فرض مفید برای بسیاری از گرهها نیست، بلکه منطق همگامسازی نیز بر آن تکیه میکند. هر جریان دارای یک مُهر زمانی محدود است که کمترین مُهر زمانی ممکن برای بسته جدید در جریان است. وقتی بسته ای با مهر زمانی T
می رسد، کران به طور خودکار به T+1
پیش می رود، که منعکس کننده نیاز یکنواخت است. این به چارچوب اجازه می دهد تا مطمئناً بداند که هیچ بسته دیگری با مهر زمانی کمتر از T
وارد نخواهد شد.
سیاست های ورودی
همگام سازی به صورت محلی در هر گره با استفاده از خط مشی ورودی مشخص شده توسط گره انجام می شود.
خط مشی ورودی پیشفرض که توسط DefaultInputStreamHandler
تعریف شده است، همگامسازی قطعی ورودیها را با تضمینهای زیر ارائه میکند:
اگر بستههایی با مهر زمانی یکسان در جریانهای ورودی متعدد ارائه شوند، بدون در نظر گرفتن ترتیب ورودشان در زمان واقعی، همیشه با هم پردازش میشوند.
مجموعههای ورودی به ترتیب مُهر زمانی کاملاً صعودی پردازش میشوند.
هیچ بسته ای حذف نمی شود و پردازش کاملاً قطعی است.
گره با توجه به تضمین های بالا در اسرع وقت آماده پردازش داده ها می شود.
برای توضیح نحوه عملکرد آن، باید تعریف مهر زمانی تسویه شده را معرفی کنیم. ما می گوییم که یک مهر زمانی در یک جریان در صورتی تسویه می شود که از مهر زمانی محدودتر باشد. به عبارت دیگر، زمانی که وضعیت ورودی در آن مُهر زمانی مشخص شد، یک مهر زمانی برای یک جریان تسویه حساب میشود: یا بستهای وجود دارد، یا این اطمینان وجود دارد که بستهای با آن مهر زمانی نمیرسد.
اگر در هر یک از آن جریانها، مهر زمانی در چندین جریان تسویه شود. علاوه بر این، اگر یک مُهر زمانی تسویه شود، به این معنی است که تمام مُهرهای زمانی قبلی نیز تسویه شده اند. بنابراین مهرهای زمانی تسویه شده را می توان به صورت قطعی به ترتیب صعودی پردازش کرد.
با توجه به این تعریف، یک ماشین حساب با خط مشی ورودی پیشفرض در صورتی آماده است که یک مهر زمانی وجود داشته باشد که در تمام جریانهای ورودی مستقر باشد و حاوی بستهای در حداقل یک جریان ورودی باشد. خط مشی ورودی همه بسته های موجود را برای یک مهر زمانی تسویه شده به عنوان یک مجموعه ورودی واحد به ماشین حساب ارائه می دهد.
یکی از پیامدهای این رفتار قطعی این است که، برای گرههایی با جریانهای ورودی متعدد، میتوان از نظر تئوری یک انتظار نامحدود برای تسویه یک مهر زمانی وجود داشت و تعداد نامحدودی از بستهها را میتوان در این فاصله بافر کرد. (گرهی را با دو جریان ورودی در نظر بگیرید، یکی از آنها به ارسال بسته ها ادامه می دهد در حالی که دیگری چیزی ارسال نمی کند و کران را پیش نمی برد.)
بنابراین، سیاستهای ورودی سفارشی را نیز در نظر میگیریم: به عنوان مثال، تقسیم ورودیها در مجموعههای همگامسازی مختلف تعریفشده توسط SyncSetInputStreamHandler
، یا اجتناب از همگامسازی به طور کلی و پردازش ورودیها بلافاصله پس از رسیدن به تعریف شده توسط ImmediateInputStreamHandler
.
کنترل جریان
دو مکانیسم اصلی کنترل جریان وجود دارد. زمانی که بستههای بافر در جریان به یک حد (قابل تنظیم) که توسط CalculatorGraphConfig::max_queue_size
تعریف شده است، میرسند، یک مکانیسم فشار برگشتی، اجرای گرههای بالادست را کاهش میدهد. این مکانیسم رفتار قطعی را حفظ می کند و شامل یک سیستم اجتناب از بن بست است که در صورت نیاز محدودیت های پیکربندی شده را کاهش می دهد.
سیستم دوم شامل درج گرههای ویژهای است که میتوانند بستهها را بر اساس محدودیتهای بلادرنگ رها کنند (معمولاً با استفاده از سیاستهای ورودی سفارشی) تعریف شده توسط FlowLimiterCalculator
. به عنوان مثال، یک الگوی رایج یک گره کنترل جریان را در ورودی یک زیرگراف قرار می دهد، با یک اتصال حلقه بک از خروجی نهایی به گره کنترل جریان. بنابراین، گره کنترل جریان میتواند تعداد مُهرهای زمانی را که در نمودار پاییندست پردازش میشوند، پیگیری کند و اگر این تعداد به یک حد (قابل تنظیم) رسید، بستهها را رها کند. و از آنجایی که بستهها در بالادست رها میشوند، از کار هدر رفته که از پردازش جزئی یک مهر زمانی و سپس انداختن بستهها بین مراحل میانی ناشی میشود اجتناب میکنیم.
این رویکرد مبتنی بر ماشین حساب به نویسنده گراف کنترل محل رها شدن بسته ها را می دهد و امکان انعطاف پذیری در تطبیق و سفارشی سازی رفتار نمودار بسته به محدودیت های منابع را فراهم می کند.