0Pricing
Java Academy · درس

الأخطاء الشائعة

الترتيب وتحويل الأنواع ومجمّع الخيوط المشترك

الأخطاء الشائعة درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.

التوازي ليس سرعة مجانية

قد يؤدي إضافة parallel() إلى جعل الشفرة أبطأ لا أسرع. يغطي هذا الدرس العقبات الشائعة حتى تتمكن من تجنبها.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long sum = IntStream.rangeClosed(1, 1_000_000).parallel()
            .asLongStream().sum();
        System.out.println(sum);
    }
}

مشكلة شائعة: تكلفة الترتيب

تفرض العمليات المرتبة مثل forEachOrdered أو limit تنسيقًا بين الخيوط، مما يقلل مكاسب التوازي.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        IntStream.rangeClosed(1, 5).parallel()
            .forEachOrdered(System.out::println);
    }
}

يمكن أن يساعد unordered

إذا لم يكن الترتيب مهمًا، فإن استدعاء unordered() يتيح لبيئة التشغيل تخطي أعمال الترتيب وتنفيذ العمليات بشكل متوازٍ بحرية أكبر.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long count = IntStream.rangeClosed(1, 1_000_000).parallel()
            .unordered()
            .filter(n -> n % 5 == 0)
            .count();
        System.out.println(count);
    }
}

مشكلة شائعة: التغليف الضمني

يؤدي استخدام Stream<Integer> بشكل متوازٍ إلى مضاعفة تكلفة التغليف بين الخيوط. فضّل التدفقات من الأنواع الأولية في العمل العددي المتوازي.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long sum = IntStream.rangeClosed(1, 1_000_000).parallel().asLongStream().sum();
        System.out.println(sum);
    }
}

مشكلة شائعة: مجموعة الخيوط المشتركة

تشارك جميع التدفقات المتوازية ForkJoinPool.commonPool() واحدة. وقد تؤدي مهمة متوازية طويلة إلى حرمان المهام الأخرى في آلة Java الافتراضية نفسها من الموارد، بما في ذلك الأجزاء الأخرى من تطبيقك.

import java.util.concurrent.ForkJoinPool;

public class Main {
    public static void main(String[] args) {
        System.out.println(ForkJoinPool.commonPool().getParallelism());
    }
}

عزل العمل في مجموعة مخصصة

لإبعاد العمل المكثف عن المجموعة المشتركة، أرسل التدفق المتوازي داخل ForkJoinPool الخاصة بك.

import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) throws Exception {
        ForkJoinPool pool = new ForkJoinPool(2);
        long sum = pool.submit(() ->
            IntStream.rangeClosed(1, 1_000_000).parallel().asLongStream().sum()
        ).get();
        pool.shutdown();
        System.out.println(sum);
    }
}

مشكلة شائعة: مصادر ضعيفة القابلية للتقسيم

تتقسم LinkedList وStream.iterate وBufferedReader.lines بشكل سيئ. وغالبًا ما يحقق تنفيذها بشكل متوازٍ فائدة ضئيلة أو سلبية.

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        long n = Stream.iterate(1, x -> x + 1)
            .limit(100_000)
            .parallel()
            .filter(x -> x % 2 == 0)
            .count();
        System.out.println(n);
    }
}

مشكلة شائعة: دوال lambda ذات الحالة

تتصرف دوال lambda التي تقرأ حالة خارجية أو تكتبها بطريقة غير حتمية عند تنفيذها بشكل متوازٍ. حافظ على خلوّها من الحالة للحصول على نتائج متسقة.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int sum = IntStream.rangeClosed(1, 100).parallel()
            .map(n -> n + 1)
            .sum();
        System.out.println(sum);
    }
}

مشكلة شائعة: findFirst مقابل findAny

يجب أن يحترم findFirst الترتيب، مما يضيف تكلفة عند التنفيذ المتوازي. فإذا كان أي عنصر مطابق مناسبًا، فاستخدم findAny.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        int found = IntStream.rangeClosed(1, 1_000_000).parallel()
            .filter(n -> n % 99991 == 0)
            .findAny()
            .getAsInt();
        System.out.println(found);
    }
}

مشكلة شائعة: عمليات قليلة التكلفة على بيانات صغيرة

في المجموعات الصغيرة جدًا أو عند تنفيذ عمل بسيط، تتجاوز تكلفة التقسيم والدمج أي فائدة محتملة. التزم بالتنفيذ التسلسلي.

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> small = List.of(1, 2, 3, 4);
        int sum = small.stream().mapToInt(Integer::intValue).sum();
        System.out.println(sum);
    }
}

مشكلة شائعة: دمج مكلف في أدوات التجميع

قد تلغي أدوات التجميع ذات خطوات الدمج المكلفة، مثل بناء هياكل مرتبة كبيرة، مكاسب التوازي. أما عمليات التجميع البسيطة فتندمج بتكلفة منخفضة.

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long total = IntStream.rangeClosed(1, 1_000_000).parallel()
            .mapToLong(n -> n)
            .sum();
        System.out.println(total);
    }
}

تحقق سريع

لماذا قد يكون findFirst أبطأ من findAny في تدفق متوازٍ؟

مراجعة

لقد تعلمت المشكلات الشائعة في التوازي:

  • يضيف الترتيب (forEachOrdered وlimit وfindFirst) تكلفة التنسيق؛ استخدم unordered أو findAny حيثما أمكن.
  • يضاعف التغليف التكلفة؛ فضّل التدفقات من الأنواع الأولية.
  • قد تستنفد المجموعة المشتركة الموارد؛ اعزل العمل المكثف في ForkJoinPool مخصصة.
  • تقلل المصادر ضعيفة القابلية للتقسيم، والبيانات الصغيرة، وعمليات الدمج المكلفة من فائدة التوازي.

الأسئلة الشائعة

هل درس «الأخطاء الشائعة» مجاني؟

نعم — نص درس «الأخطاء الشائعة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «الأخطاء الشائعة»؟

الترتيب وتحويل الأنواع ومجمّع الخيوط المشترك تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «الأخطاء الشائعة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. إنشاء التدفقات المتوازية
  2. متى تفيد المعالجة المتوازية
  3. سلامة الخيوط والآثار الجانبية
  4. الأخطاء الشائعة
← العودة إلى Java Academy