تفاوت بین نخ معمولی و نخ مجازی در جاوا — از صفر تا صد

۲۱۵ بازدید
آخرین به‌روزرسانی: ۰۵ شهریور ۱۴۰۲
زمان مطالعه: ۴ دقیقه
تفاوت بین نخ معمولی و نخ مجازی در جاوا — از صفر تا صد

در این مقاله به بررسی تفاوت‌های بین نخ معمولی و نخ مجازی در جاوا می‌پردازیم. سپس چندین کاربرد نخ‌های مجازی (Virtual Threads) و API‌-های مربوطه را معرفی می‌کنیم. بدین منظور از پروژه Loom (+) بهره خواهیم گرفت.

پیش از آغاز باید اشاره کنیم که این پروژه هم اینک در حال توسعه است. ما مثال‌های خود را بنا بر دسترسی قبل از موعدی که به فایل این پروژه (openjdk-15-loom+4-55_windows-x64_bin) داشتیم اجرا می‌کنیم.

نسخه‌های جدیدتر این پروژه تغییر یافته‌اند و با API-های کنونی سازگاری ندارند. معنی این حرف آن است که هم اینک تغییر عمده‌ای در API رخ داده است، چون کلاسی که قبلاً با نام java.lang.Fiber استفاده می‌کردیم، حذف شده و به جای آن با کلاس جدید java.lang.VirtualThread کار می‌کنیم.

مقایسه کلی نخ معمولی و نخ مجازی در جاوا

از دید سطح بالا نخ معمولی از سوی سیستم عامل، مدیریت و زمان‌بندی می‌شود،‌ در حالی که نخ مجازی از سوی ماشین مجازی مدیریت و زمان‌بندی می‌شود. بنابراین برای ایجاد نخ کرنل جدید باید یک فراخوانی سیستمی داشته باشیم و این کار از نظر عملیاتی پرهزینه است.

به همین دلیل است که از «استخر نخ» (Thread Pool) به جای تخصیص مجدد و آزادسازی نخ‌ها در موارد نیاز استفاده می‌کنیم. به این ترتیب اگر بخواهیم اپلیکیشن خود را با افزودن نخ‌های بیشتر مقیاس‌بندی کنیم، به دلیل وجود چیزی به نام «سوئیچ زمینه» (context switching) و اثر آن بر حافظه، هزینه دست‌کاری این نخ‌ها ممکن است چشمگیر باشد و روی زمان پردازش تأثیر بگذارد.

بنابراین به طور معمول تمایلی به مسدودسازی این نخ‌ها نداریم و این کار موجب رواج استفاده از API-های نامسدودساز I/O و API-های ناهمگام می‌شود که ممکن است کد را شلوغ کنند.

از سوی دیگر نخ‌های مجازی از سوی JVM مدیریت می‌شوند. از این رو تخصیص آن‌ها نیازمند یک فراخوانی سیستمی نیست و از سوئیچ زمینه سیستم عامل آزاد هستند. به علاوه نخ‌های مجازی روی نخ حامل اجرا می‌شوند که نخ واقعی کرنل است که در پس‌زمینه مورد استفاده قرار می‌گیرد. در نتیجه چون از سوئیچ زمینه سیستم آزاد شده‌ایم، می‌توانیم نخ‌های مجازی بسیار بیشتری را به کار بگیریم.

یک مشخصه کلیدی نخ‌های مجازی این است که نخ حامل را مسدود نمی‌سازند. به این ترتیب مسدودسازی یک نخ مجازی به عملیاتی بسیار ارزان‌تر تبدیل می‌شود، چون HVM نخ مجازی دیگری را زمان‌بندی می‌کند و نخ حامل مسدود نمی‌شود.

API جدید Builder برای نخ

در Loom یک API جدید builder در کلاس Thread داریم که همراه با چند متد factory دیگر ارائه شده است. در این بخش به بررسی شیوه ایجاد کارخانه‌های استاندارد و مجازی و بهره‌گیری از آن‌ها برای اجرای نخ خود می‌پردازیم:

1Runnable printThread = () -> System.out.println(Thread.currentThread());
2         
3ThreadFactory virtualThreadFactory = Thread.builder().virtual().factory();
4ThreadFactory kernelThreadFactory = Thread.builder().factory();
5 
6Thread virtualThread = virtualThreadFactory.newThread(printThread);
7Thread kernelThread = kernelThreadFactory.newThread(printThread);
8 
9virtualThread.start();
10kernelThread.start();

خروجی اجرای کد فوق به صورت زیر است:

1Thread[Thread-0,5,main]
2VirtualThread[<unnamed>,ForkJoinPool-1-worker-3,CarrierThreads]

مدخل نخست خروجی استاندارد toString مربوط به نخ کرنل است. اکنون در خروجی می‌بینیم که نخ مجازی هیچ نامی ندارد و روی نخ کارگر از استخر Fork-Join مربوط به گروه نخ‌های CarrierThreads اجرا می‌شود.

چنان که می‌بینیم صرف‌نظر از پیاده‌سازی زیرین، API همان است و معنی این گفته آن است که می‌توانیم به سادگی کد موجود را روی نخ‌های مجازی اجرا کنیم. ضمناً نیازی به یادگیری API جدید برای بهره‌گیری از این نخ‌های مجازی نداریم.

نخ مجازی در جاوا

ترکیب‌بندی نخ مجازی در جاوا

نخ مجازی از ترکیب یک continuation و یک scheduler ساخته می‌شود. این scheduler حالت کاربر می‌تواند هر پیاده‌سازی از اینترفیس Executor باشد. مثال فوق به ما نشان داد که به طور پیش‌فرض کد روی ForkJoinPool اجرا می‌شود.

به طور مشابه برای یک نخ کرنل که می‌تواند روی CPU اجرا شود و سپس پارک شده و مجدداً زمان‌بندی شود و سپس اجرای خود را تعلیق کند، یک continuation واحدی اجرایی است که می‌تواند آغاز شود و سپس پارک شود و مجدداً زمان‌بندی شده و اجرای خود را به ترتیبی تعلیق کند که کار را از جای باقیمانده از سر بگیرد و همه این موارد در حالی است که به جای سیستم عامل به وسیله JVM مدیریت می‌شود.

توجه کنید که continuation یک API سطح پایین است و برنامه‌نویس‌ها باید از API-های سطح کرنل مانند builder API برای اجرای نخ‌های مجازی بهره بگیرند. با این حال برای این که نشان دهیم طرز کار آن در پس‌زمینه چگونه است یک continuation آزمایشی را اجرا می‌کنیم:

1var scope = new ContinuationScope("C1");
2var c = new Continuation(scope, () -> {
3    System.out.println("Start C1");
4    Continuation.yield(scope);
5    System.out.println("End C1");
6});
7 
8while (!c.isDone()) {
9    System.out.println("Start run()");
10    c.run();
11    System.out.println("End run()");
12}

خروجی اجرای کد فوق به صورت زیر است:

1Start run()
2Start C1
3End run()
4Start run()
5End C1
6End run()

در این مثال، continuation خود را اجرا می‌کنیم و در نقطه‌ای از زمان تصمیم می‌گیریم که پردازش را متوقف کنیم. سپس در ادامه دوباره آن را اجرا می‌کنیم. بدین ترتیب continuation ما از جایی که کار را متوقف کرده بود از سر می‌گیرد. از روی خروجی متوجه می‌شویم که متد run()‎ دو بار فراخوانی شده است، اما continuation یک بار آغاز شده و سپس اجرای خود را در اجرای دوم از جایی که باقی مانده بود، از سر گرفته است.

ما می‌خواهیم که عملیات مسدودساز از سوی JVM به این صورت اجرا شوند. زمانی که عملیات مسدودساز رخ می‌دهد، continuation تعلیق می‌شود و نخ حامل مسدود نمی‌شود. بنابراین اتفاقی که افتاده این است که نخ اصلی یک فریم پشته جدید روی پشته فراخوانی خود برای متد ()run ایجاد کرده و اجرا را تداوم بخشیده است. سپس بعد از آن که continuation تعلیق شد، JVM حالت کنونی اجرای آن را ذخیره کرده است.

در ادامه نخ اصلی اجرای خود را طوری ادامه داده که گویی متد ()run بازگشته است و با حلقه loop ادامه داده است. پس از فراخوانی دوم به متد ()run در continuation ،JVM حالت نخ اصلی را به نقطه‌ای بازیابی کرده که continuation تعلیق شده بود و اجرا را خاتمه بخشیده است.

سخن پایانی

در این مقاله به بررسی تفاوت بین نخ کرنل و نخ مجازی پرداختیم. سپس شیوه استفاده از API بیلدر جدید از پروژه Loom برای اجرای نخ مجازی را نشان دادیم. در نهایت نشان دادیم که یک continuation چیست و چگونه کار می‌کند. همچنین به بررسی حالت پروژه Loom پرداختیم.

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
baeldung
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *