جمع آوری زباله های پایتون دوستانه برای کپی نوشتن

در اینستاگرام ، ما بزرگترین استقرار چارچوب وب Django را در جهان داریم که کاملاً در پایتون نوشته شده است. ما از اوایل شروع به استفاده از پایتون به دلیل سادگی آن کردیم ، اما در طول سال ها مجبور شدیم هک های زیادی انجام دهیم تا همانطور که مقیاس بندی کردیم ، ساده باشیم. سال گذشته ما سعی کردیم مکانیسم جمع آوری زباله پایتون (GC) (که با جمع آوری و آزاد سازی داده های استفاده نشده حافظه را بازیابی می کند) را رد کنیم و 10٪ ظرفیت بیشتری کسب کردیم. با این حال ، با افزایش تیم مهندسی و تعداد ویژگی های ما ، استفاده از حافظه نیز رشد کرده است. سرانجام ، ما دستاوردهایی را که با غیرفعال کردن GC بدست آورده بودیم ، از دست دادیم. این یک نمودار است که نشان می دهد چگونه حافظه ما با تعداد درخواست ها رشد می کند. پس از 3000 درخواست ، پردازش از 600 مگابایت حافظه بیشتر استفاده کرد. از همه مهمتر ، روند خطی بود.

از با آزمایش بار ، می توانستیم ببینیم که استفاده از حافظه به گلوگاه ما تبدیل شده است. فعال کردن GC می تواند این مشکل را کاهش داده و رشد حافظه را کند کند ، اما هنوز هم Copy on-write (COW) نامطلوب باعث افزایش ردپای حافظه می شود. بنابراین ما تصمیم گرفتیم ببینیم آیا می توانیم Python GC را بدون COW کار کنیم و از این رو ، حافظه سربار است.

قرمز: بدون GC؛ آبی: تماس با GC صریحاً جمع می شود. سبز: پیش فرض Python GC فعال است

اول سعی کنید: ساختار داده سر GC را دوباره طراحی کنید

اگر آخرین پست GC ما را با دقت بخوانید ، متوجه خواهید شد که مقصر COW از آن جلوتر است هر شی پایتون:

 /* اطلاعات GC قبل از ساختار شی ذخیره می شود. * /typedef union _gc_head
{
    ساختار {
        اتحادیه _gc_head * gc_next؛
        اتحادیه _gc_head * gc_prev؛
        Py_ssize_t gc_refs؛
    } gc؛
    ساختگی دوتایی بلند ؛ /* همترازی در بدترین حالت را اعمال کنید * /} PyGC_Head؛ 

این نظریه این بود که هر بار که مجموعه ای را انجام می دهیم ، gc_refs را با ob_refcnt برای همه اشیا track ردیابی شده به روز می کند - اما متأسفانه این کار نوشتن باعث می شود صفحات حافظه به صورت COW ویرایش شوند. یک راه حل واضح بعدی این بود که همه سر را به قسمت دیگری از حافظه منتقل کنید و به صورت فشرده ذخیره کنید. ما نسخه ای را اجرا کردیم که نشانگر در ساختار gc_head در حین جمع آوری تغییر نکرده است:

 typedef union _gc_head_ptr
{
    ساختار {
        اتحادیه _gc_head * سر ؛
    } gc_ptr؛
    ساختگی دوتایی /* همترازی در بدترین حالت را اعمال کنید * /} PyGC_Head_Ptr ؛ 

آیا کار کرد؟ ما از اسکریپت زیر برای اختصاص دادن حافظه و چنگال پردازش کودک برای آزمایش آن استفاده کردیم:

 لیست = []
strs = [] 
 برای من در محدوده (16000):
    list.append ([])
    برای j در محدوده (40):
        strs.append ('' * 8) 

با ساختار قدیمی gc_head ، میزان حافظه RSS فرآیند کودک 60 مگابایت افزایش یافت. در ساختار داده جدید با اشاره گر اضافی ، فقط 0.9 مگابایت ~ افزایش یافته است. بنابراین کار کرد! با این حال ، ممکن است متوجه شده باشید که اشاره گر اضافی در ساختار داده پیشنهادی ، حافظه جانبی را معرفی کرده است (16 بایت - دو نشانگر). به نظر می رسد تعداد کمی است ، اما اگرشما فکر می کنید که این مورد برای هر شی جمع آوری شده Python اعمال می شود (و ما معمولاً میلیون ها شی را در یک فرایند داریم ، با 70 پوند پردازش برای هر میزبان) ، این می تواند یک حافظه نسبتاً بزرگ در بالای سرور باشد.

16 بایت * 1،000،000 * 70 = ~ 1 GB

تلاش دوم: مخفی کردن اشیا shared مشترک از GC

حتی اگر ساختار جدید داده gc_head سودهای امیدوارکننده ای را در اندازه حافظه نشان دهد ، سربار آن ایده آل نبود. ما می خواستیم راه حلی پیدا کنیم که بتواند GC را تحت تأثیر عملکرد قابل توجه قرار دهد. از آنجا که مشکل ما فقط مربوط به اشیا shared مشترک است که قبل از انشعاب فرآیندهای کودک در فرآیند اصلی ایجاد می شوند ، سعی کردیم که Python GC با اشیا shared مشترک به گونه دیگری برخورد کند. به عبارت دیگر ، اگر می توانستیم اشیا shared مشترک را از مکانیزم GC پنهان کنیم تا در چرخه جمع آوری GC مورد بررسی قرار نگیرند ، مشکل ما حل می شود. برای این منظور ، ما یک API ساده به عنوان gc.freeze () به ماژول Python GC اضافه کردیم تا اشیا from را از لیست نسل Python GC که توسط Python داخلی برای ردیابی اشیا for برای جمع آوری نگهداری می شود ، حذف کنیم. ما این تغییر را در پایتون انجام داده ایم و API جدید در نسخه Python3.7 (https://github.com/python/cpython/pull/3705) در دسترس خواهد بود.

 استاتیک PyObject *
gc_freeze_impl (ماژول PyObject *)
{
    برای (int i = 0؛ i  

موفقیت!

ما این تغییر را در تولید خود قرار دادیم و این بار مطابق انتظار عمل کرد: COW دیگر اتفاق نیفتاد و حافظه مشترک ثابت ماند ، در حالی که رشد حافظه به ازای هر درخواست کاهش یافت ~ 50 نمودار زیر نشان می دهد که چگونه GC با متوقف کردن رشد خطی و طولانی تر کردن روند کار ، به رشد حافظه کمک می کند.

آبی: no-GC است؛ قرمز: auto-GC

اعتبارات

با تشکر از جیاهائو لی ، مت پیج ، دیوید کالاهان ، کارل اس. شاپیرو و چنیانگ وو برای بحث ها و مشارکت های خود در پایتون دوستدار COW جمع آوری زباله.

ز لی مهندس زیرساخت در اینستاگرام است.


چگونه می توان به عنوان نویسنده در اینستاگرام رشد کرد

اعلام # n1ceview قرعه کشی اینستاگرام

جمع آوری زباله های پایتون دوستانه برای کپی نوشتن

چگونه می توان به عنوان نویسنده در اینستاگرام رشد کرد

چه چیزی باعث ایجاد یک آرم خوب می شود و چه چیزهایی می توانیم از اینستاگرام یاد بگیریم.

چرا فرهنگ اینستاگرام Is Made Up BS

مادری در عصر مامان ترد اینستاگرام

gc ,، ,حافظه ,* ,head ,ساختار ,gc head ,می شود ,جمع آوری ,python gc ,shared مشترک ,اشیا shared مشترک

مشخصات

آخرین ارسال ها

خرید سکه ساکر استارز محل تبلیغات شما محل تبلیغات شما

آخرین جستجو ها

Peter's page javooni پونی کوچولو انسانی 19563549 فروشگاه ستاره cementboard Carlos's game negarehkbaran بیست رپ 17223654