April 18, 2015

Parallel Stream

ပြီးခဲ့သော အခန်းများတွင် Stream API အကြောင်းကို မိတ်ဆက်ခဲ့ပါသည်။ Stream API သည် Stream အတွင်းရှိ Element များအား Pipe Line Operation ဖြင့်ဆောင်ရွက်စေနိုင်သော API တစ်ခု ဖြစ်ပါသည်။ Stream API တွင် ယခု တိုင် Java Programming Language တွင်ပါဝင်ခြင်း မရှိခဲ့သေးသော Internal Iteration Controls ကို အသုံးပြုလာခဲသည်။ ဤအချက်သည် Parallel Operation ကို လွယ်ကူစွာ ဆောင်ရွက်လာစေနိုင်ပါသည်။

Parallel Operation ဆိုသည်မှာ လုပ်ဆောင်မှု့တစ်ခုကို Tread တစ်ခုဆောင်ရွက်နေစဥ် အခြားသော ဆောင်ရွက်မှု့များကို ဆောင်ရွက်စေခြင်းဖြစ်ပါသည်။ ဘာ့ကြောင့် ဒီလိုအချိန်မှာ Parallel Operation အကြောင်းကို ဆောင်ရွက်လာကြသနည်း။ ကျွန်တော်တို့ လက်ရှိ အသုံးပြုနေသော Computer များသည် ယခင် ၁၀နှစ်ကျော်ကနှင့် စာလျင် လွန်စွာတိုးတက်လာခဲပါသည်။ ယခင်က Pan 2, 3, 4 ဆိုလျင် ဟုတ်လှခြည်လားဟု တွေးမိမည်ဆိုသော်လဲ၊ Core i 3, 5, 7 ဖြင့် Core တွေများပြားလာခဲ့ပါသည်။ Memory ဆိုလျင်လဲ အနည်းဆုံး 2G, 4G, 8G နှင် 16G အထိသုံးလာကြ၏။ လုပ်ငန်းသုံးများဆိုပါက CUP ကို ပင် အလုံးပေါင်းများစွာ အသုံးပြုလာကြ၏။

Programming Language ဘက်ကတော့ Hardware တိုးတက်မှု့နှင်စာလျင် တိုးတက်မှု့ နည်းပါးပါသေးသည်။ Hardware များ၏​ စွမ်းရည်အား အပြည့်အဝ အသုံးခြနိုင်အောင်ပြင်ဆင်မှု့နည်းပါးပါသေးသည်။ Java Programming သည် ကနဦးဗားရှင်း ကတည်းက Multi Thread ကို အသုံးပြုနိုင်ခဲ့သော်လဲ၊ CPU ၏ Core အားလုံးအား ပြည့်ပြည့်ဝဝ အသုံးခြလာနိုင်ခဲ့သည်တော့ မဟုတ်။ ထို့ကြောင့် Java SE 7 ကတည်းက စပြီး Parallel Operation များကို အသုံးပြုနိုင်ရန် ပြင်ဆင်မှု့များကို စတင်ပြင်ဆင်လာခဲ့၏။

Parallel Operation ၏ အခြေခံသဘောတရားမှာ အလွန်ကြီးမားသော ပြဿနာတစ်ခုရှိပါက အစအဆုံးအား တစ်ယောက်တည်း အစအဆုံးဖြေရှင်းနေသည်ထက်စာလျင်၊ ပြဿနာအား သေးငယ်သော ပြဿနာများ အဖြစ် အပိုင်းပိုင်းခွဲကာ လူအများနှင့် စုပေါင်းဖြေရှင်း၍ အဖြေစုစုပေါင်းအားရှာဖွေသည်က ပို၍မြန်ဆန်လွယ်ကူနိုင်စေမည်ဖြစ်သည်။ ထိုကြောင့် Java SE 7 တွင် Fork And Join အား ဖြည့် စွက်လာခဲ့ပြီး Thread အများဖြင့် ဆောင်ရွက်လာစေနိုင်ခဲ့ပါသည်။




သို့ရာတွင် Fork လုပ်ရာတွင် မည်ကဲ့သို့ခွဲမည်ဆိုသည်ကပြဿနာတစ်ခုဖြစ်လာပါသည်။ မည်ကဲသို့ ခွဲမည်ဆိုသည်ကို ပရိုဂရမ်မာများက ကိုယ့်ဟာကို ရေးသားရန်လို အပ်နေပါသေးသည်။ Java SE 7 အထိ Java Programming တွင် Iteration Process များအား for, while တို့အား အသုံးပြု၍ Control လုပ်ကြရပါသည်။ အဆိုပါ Iteration အမျိုးအစားအား External Iteration Control ဟု ခေါ်ဆိုပါသည်။ External Iteration Control များသည် API မှ Operation များကို ဖြည့်စွက်ရန်ခက်ခဲခဲ့ပါသည်။

ထို့ကြောင့် Java SE 8 အရောက်တွင် Collection Framework နှင့် Stream API တို့တွင် Internal Iteration Control များအား ဖြည့်စွက်လာခဲ့ပါသည်။ ထို့အပြင် Stream API တွင် Parallel Stream ကို လဲ ဖြည့်စွက်လာနိုင်ပြီး API ဘက်မှ Parallel Operation အား အပြည့်အဝပံ့ပိုးလာနိုင်ခဲ့ပါသည်။

တစ်ခုသတိပြုရန်မှာ Parallel Operation ကို နေရာတကာ အသုံးပြု၍ကောင်းသည်မဟုတ်။ ဥပမာအား ဖြင့် တစ်ဦးတည်း ဖြေရှင်းနိုင်သော ပြဿနာအား လူအများကို ခွဲနေပါမှမလိုအပ်ပဲကြံ့ကြာနေပါမည်။ ထို့ကြောင့် သင့်တော်သော Operation များကိုသာ Parallel Operation နှင့်လုပ်ဆောင်သင့်ပါသည်။


Creating Parallel Stream


Parallel Stream ဟု ဆိုသော်လဲ ၎င်းအတွက်သီးခြား Interface ကို အသုံးပြုနေခြင်း မဟုတ်။ Stream တွင် အသုံးပြုခဲ့သော Stream, IntStream တို့ကို သာ အသုံးပြုနေပါသည်။ ထူးခြားသည်မှာ Stream အားစတင်စေသော နေရာတွင်ဖြစ်ပါသည်။

Parallel Stream အားရရှိလိုပါက Collection#parallelStream method နှင့် Stream#parallel method ကို အသုံးပြုနိုင်၏။ ထို့အပြင် Parallel Stream မှ သာမန် Stream ကို ရယူလိုပါက squential method အား အသုံးပြုနိုင်ပါသည်။
  List<String> list = Arrays.asList("a", "b", "c");
  Stream<String> pStream1 = list.parallelStream();
  
  IntStream pStream2 = IntStream.range(1, 10).parallel();


Ordering of Parallel Stream


Parallel Stream များသည် Stream အတွင်းရှိ Element များအား တစ်ပြိုင်နက်တည်း လုပ်ဆောင်မှု့များအား ဆောင်ရွက်စေနိုင်ရန်အတွက် Multi Thread များကို အသုံးပြုဆောင်ရွက်နေပါသည်။ ထို့ကြောင့်သာမန်အားဖြင့် နဂိုမူလ အစီအစဥ်အား ထိမ်းသိမ်းပေးထားနိုင်မည်မဟုတ်။ အရင်ပြီးဆုံးသည့် Thread အတွင်းမှ Element သည်နောက်ဆုံးသို့ အရင်ရောက်ရှိလာမည်ဖြစ်ပါသည်။
 public static void main(String[] args) {
  IntStream.range(1, 10)
   .parallel().filter(a -> a % 2 == 1)
   .forEach(System.out::println);;
 }

အထက်ပါကုဒ်များအား Run ကြည့်ပါက 1,3,5,7,9 ဟု အစီအစဥ်အတိုင်းထွက်မည်မဟုတ်။ အစီအစဥ်အတိုင်း ထွက်ပေါ်စေလိုပါက forEach method အစား forEachOrdered အားအသုံးပြုရမည်ဖြစ်သည်။


Converting To Map


Stream မှ Map Object သို့ပြောင်းလဲရန် Collectors Class ၏ groupingBy နှင့် mapTo မက်သတ်တို့ကို အသုံးပြုနိုင်သည်။ Parallel Stream များတွင်လဲ အဆိုပါ မက်သတ်များကို အသုံးပြုနိုင်ပါသည်။ သို့ရာတွင် groupingByConcurrent နှင့် toConcurrentMap တို့ကိုလဲအသုံးပြုနိုင်ပါသည်။ အဆိုပါ မက်သတ်များ၏​ Return Type သည် java.urtil.concurrent.ConcurrentMap Interface ဖြစ်သည်။

ဤကဲ့သို့ ConcurrentMap အား အသုံးပြုခြင်းအားဖြင့် Parallel Stream လုပ်ဆောင်ချက် Performance အား ပိုမိုကောင်းမွန်စေမည် ဖြစ်ပါသည်။
    static class Student {
        private long id;
        private String name;
        private String address;
        private String township;
        
        // getters and setters
        
    }
    
    public static void main(String[] args) {
        List<Student> list = getStudents();
        
        ConcurrentMap<String, List<Student>> map = list.parallelStream()
                .collect(Collectors.groupingByConcurrent(a -> a.getTownship()));
    }

အထက်ပါနမူနာသည် Student List မှ township တန်ဖိုးတူသည့် Map အားရယူနေခြင်းဖြစ်ပါသည်။ groupingBy မက်သတ်အား အသုံးပြုပါက ရလဒ်မှာ အတူတူပင်ဖြစ်သော်လဲ Parallel Stream ဖြစ်သောကြောင့် groupingByConcurrent ကို အသုံးပြုခြင်းက Performance ကို ပိုမိုကောင်းမွန် စေပါသည်။


ဆက်ပါမည်။ ကျေးဇူးတင်စွာဖြင့်
မင်းလွင်

No comments:

Post a Comment