Flow؛ زبانی که همروندی اکتور رو به C++ آورد
خلاصهٔ کاملتر
به گفتهٔ تیم FoundationDB، اونها موقع ساخت هستهٔ دیتابیس با یه چالش سهگانه روبهرو بودن: هم کارایی و بازدهی I/O بالای C++ رو میخواستن، هم مدل همروندیِ راحت و پیاممحورِ اکتور (چیزی شبیه Erlang یا Async تو داتنت)، و هم امکان شبیهسازیِ گسترده برای تست پایداری. جوابشون به این چالش، ساخت یه زبان جدید به اسم Flow بود.
Flow در واقع یه سری کلمهٔ کلیدی و ساختار کنترلیِ جدید به C++11 اضافه میکنه. یه کامپایلر جداگونه، تابعهای ناهمگام (اکتورها) رو میگیره و بازنویسیشون میکنه به کدی که با callback کار میکنه تا جلوی بلاکشدن گرفته شه. خروجی این کامپایلر C++11 استاندارده که با ابزارهای معمولی به باینری تبدیل میشه.
قلب مدل، دو نوع دادهٔ Promise و Future هست. فرستنده یه Promise نگه میداره یعنی قول میده یه مقدار رو در آینده تحویل بده، و گیرنده که Future داره میتونه تا وقتی واقعاً به اون مقدار نیاز پیدا کنه، محاسبهش رو ادامه بده. جالبیش اینه که این جفت میتونه از شبکه هم رد شه؛ یعنی یه ماشین Promise رو برای ماشین دیگه بفرسته و وقتی مقدار پر شد، سمت مقابل اون رو ببینه.
دستور wait() جاییه که یه اکتور تا آمادهشدن مقدار Future مکث میکنه، ولی این مکث بقیهٔ اکتورها رو متوقف نمیکنه؛ همین باعث همروندیِ ناهمگام تو یه پروسه میشه. فقط تابعهایی که با تگ ACTOR علامت خوردن اجازهٔ صدازدن wait() رو دارن. یه اکتور ساده که یه مقدار رو منتظر میمونه و با یه آفست جمع میزنه، اینشکلیه:
ACTOR Future<int> asyncAdd(Future<int> f, int offset) {
int value = wait( f );
return value + offset;
}برای کار با جریانی از پیامها به جای یه پیام تکی هم PromiseStream و FutureStream هست، و ساختار choose … when اجازه میده یه اکتور همزمان منتظر چند Future بمونه. کلمهٔ کلیدی state هم متغیری رو تعریف میکنه که بین چند wait() داخل یه اکتور زنده میمونه.
منتها Flow یه سری قلق داره که تیم روش تأکید کرده: کدش شبیه C++ هست ولی C++ نیست. مثلاً متغیرهای محلی از یه wait جون سالم به در نمیبرن، this باید با THIS جایگزین شه تا پشتیبانی IDE نشکنه، و متغیرهای state قواعد اسکوپ معمولی رو دنبال نمیکنن؛ برای همین بهتره تو بیرونیترین اسکوپ تعریفشون کنی.
نکات کلیدی:
- Flow همروندیِ مبتنی بر اکتور رو به C++11 اضافه میکنه و به C++ معمولی کامپایل میشه
- جفت Promise/Future فرستنده و گیرندهٔ پیامهای ناهمگام رو وصل میکنه و حتی از شبکه رد میشه
- wait() فقط داخل تابعهای ACTOR مجازه و بدون بلاککردن بقیهٔ اکتورها مکث میکنه
- Flow ورودیِ ابزار شبیهسازیِ قطعی رو هم میده تا خطاها و خرابیها روی کلاستر بزرگ تست شن
- کد Flow قلقهایی داره؛ مثلاً متغیر محلی بعد از wait از بین میره




