वेधशालाओं की एक सूची को संयोजित करें और सभी पूर्ण होने तक प्रतीक्षा करें


91

टी एल; डॉ कैसे कन्वर्ट करने के लिए Task.whenAll(List<Task>)में RxJava?

मेरा मौजूदा कोड बोल्ट्स का उपयोग करता है अतुल्यकालिक कार्यों की सूची बनाने के लिए और अन्य चरणों का प्रदर्शन करने से पहले उन सभी कार्यों के पूरा होने तक इंतजार करता है। अनिवार्य रूप से, यह एक बनाता है List<Task>और एक एकल लौटाता है Taskजिसे पूरा होने के रूप में चिह्नित किया जाता है जब सूची में सभी कार्य बोल्ट साइट पर उदाहरण के अनुसार पूर्ण होते हैं ।

मैं के Boltsसाथ बदलने के लिए देख रहा हूँ RxJavaऔर मैं async कार्यों की एक सूची (आकार अग्रिम में ज्ञात नहीं है) और उन सभी को एक एकल में लपेटना Observableसंभव है, लेकिन मैं नहीं जानता कि कैसे।

मैं पर देख रहे हैं की कोशिश की किया है merge, zip, concatआदि ... लेकिन नहीं पर काम करने के लिए प्राप्त कर सकते हैं List<Observable>कि मैं का निर्माण होगी के रूप में वे सभी पर काम कर सिर्फ दो के लिए तैयार लग Observablesएक समय में अगर मैं डॉक्स सही ढंग से समझ।

मैं सीखने की कोशिश कर रहा हूं RxJavaऔर अभी भी बहुत नया हूं इसलिए मुझे माफ कर दें अगर यह एक स्पष्ट सवाल है या कहीं डॉक्स में समझाया गया है; मैंने खोज करने की कोशिश की है। कोई भी सहायताकाफी प्रशंसनीय होगी।

जवाबों:


73

ऐसा लगता है कि आप जिप ऑपरेटर की तलाश कर रहे हैं ।

इसका उपयोग करने के कुछ अलग तरीके हैं, तो आइए एक उदाहरण देखें। कहें कि हमारे पास विभिन्न प्रकार के कुछ सरल वेधशालाएं हैं:

Observable<Integer> obs1 = Observable.just(1);
Observable<String> obs2 = Observable.just("Blah");
Observable<Boolean> obs3 = Observable.just(true);

उन सभी के लिए इंतजार करने का सबसे सरल तरीका कुछ इस प्रकार है:

Observable.zip(obs1, obs2, obs3, (Integer i, String s, Boolean b) -> i + " " + s + " " + b)
.subscribe(str -> System.out.println(str));

ध्यान दें कि जिप फ़ंक्शन में, मापदंडों में ठोस प्रकार होते हैं जो कि वेधशालाओं के प्रकार के अनुरूप होते हैं।

वेधशालाओं की सूची ज़िप करना भी संभव है, या तो सीधे:

List<Observable<?>> obsList = Arrays.asList(obs1, obs2, obs3);

Observable.zip(obsList, (i) -> i[0] + " " + i[1] + " " + i[2])
.subscribe(str -> System.out.println(str));

... या सूची को एक में लपेटकर Observable<Observable<?>>:

Observable<Observable<?>> obsObs = Observable.from(obsList);

Observable.zip(obsObs, (i) -> i[0] + " " + i[1] + " " + i[2])
.subscribe(str -> System.out.println(str));

हालांकि, इन दोनों मामलों में, जिप फ़ंक्शन केवल एक ही Object[]पैरामीटर को स्वीकार कर सकता है क्योंकि सूची में वेधशालाओं के प्रकार अग्रिम में और साथ ही उनकी संख्या के बारे में नहीं जानते हैं। इसका मतलब यह है कि जिप फ़ंक्शन को मापदंडों की संख्या की जांच करनी होगी और उन्हें तदनुसार डाली जाएगी।

भले ही, उपरोक्त सभी उदाहरण अंततः मुद्रित होंगे 1 Blah true

EDIT: ज़िप का उपयोग करते समय, सुनिश्चित करें कि Observablesजाँचा हुआ सभी समान आइटमों का उत्सर्जन करते हैं। उपरोक्त उदाहरणों में तीनों वेधशालाओं ने एक ही वस्तु का उत्सर्जन किया। अगर हम उन्हें कुछ इस तरह से बदल रहे थे:

Observable<Integer> obs1 = Observable.from(new Integer[]{1,2,3}); //Emits three items
Observable<String> obs2 = Observable.from(new String[]{"Blah","Hello"}); //Emits two items
Observable<Boolean> obs3 = Observable.from(new Boolean[]{true,true}); //Emits two items

तो फिर 1, Blah, Trueऔर 2, Hello, Trueज़िप समारोह (रों) में पारित केवल आइटम होगा। 3अन्य वेधशालाएं पूरी होने के बाद से आइटम को कभी भी ज़िप नहीं किया जाएगा।


9
यदि कॉल विफल हो जाती है तो यह काम नहीं करेगा। उस स्थिति में सभी कॉल खो जाएंगे।
StarWind0

1
@ StarWind0 आप उपयोग द्वारा त्रुटि को छोड़ सकते हैं onErrorResumeNext, उदाहरण:Observable.zip(ob1, ob2........).onErrorResumeNext(Observable.<String>empty())
vuhung3990

यदि मेरे पास 100 वेधशालाएं हैं तो क्या होगा?
क्रिज़ीस्तोफ़ कुबिकी

80

आप flatMapगतिशील कार्य संरचना के मामले में उपयोग कर सकते हैं । कुछ इस तरह:

public Observable<Boolean> whenAll(List<Observable<Boolean>> tasks) {
    return Observable.from(tasks)
            //execute in parallel
            .flatMap(task -> task.observeOn(Schedulers.computation()))
            //wait, until all task are executed
            //be aware, all your observable should emit onComplemete event
            //otherwise you will wait forever
            .toList()
            //could implement more intelligent logic. eg. check that everything is successful
            .map(results -> true);
}

समानांतर निष्पादन का एक और अच्छा उदाहरण

नोट: मैं वास्तव में त्रुटि से निपटने के लिए आपकी आवश्यकताओं को नहीं जानता। उदाहरण के लिए क्या करें यदि केवल एक कार्य विफल हो जाए। मुझे लगता है कि आपको इस परिदृश्य को सत्यापित करना चाहिए।


17
यह उस प्रश्न पर विचार करते हुए स्वीकृत उत्तर होना चाहिए "जब सूची में सभी कार्य पूर्ण हो जाते हैं"। zipजैसे ही कोई कार्य पूरा हो जाता है और इस तरह लागू नहीं होता है, पूरा होने के बारे में सूचित करता है।
user3707125

1
@MyDogTom: क्या आप जावा 7 सिंटैक्स (लैम्बडा नहीं) संस्करण के साथ उत्तर को अपडेट कर सकते हैं?
sanedroid

3
@PoojaGaikwad लांबड़ा के साथ यह अधिक पठनीय है। बस पहले लैम्ब्डा को बदलें new Func1<Observable<Boolean>, Observable<Boolean>>()...और दूसरे कोnew Func1<List<Boolean>, Boolean>()
MyDogTom

@ सोशियल RxJava 2 सबसे बुरी चीज है जो कभी RxJava के साथ हुई है, हाँ
egorikem

16

प्रस्तावित सुझावों में से, ज़िप () वास्तव में एक-दूसरे के साथ अवलोकन योग्य परिणामों को जोड़ता है, जो कि वांछित है या नहीं हो सकता है, लेकिन प्रश्न में नहीं पूछा गया था। प्रश्न में, वह सब कुछ था जो प्रत्येक ऑपरेशन का निष्पादन था, या तो एक-एक करके या समानांतर में (जो निर्दिष्ट नहीं था, लेकिन जुड़ा बोल्ट उदाहरण समानांतर निष्पादन के बारे में था)। इसके अलावा, जब कोई भी वेधशाला पूरी हो जाती है, तो ज़िप () तुरंत पूरा हो जाएगा, इसलिए यह आवश्यकताओं का उल्लंघन है।

वेधशालाओं के समानांतर निष्पादन के लिए, अन्य उत्तर में प्रस्तुत किए गए फ्लैटपाइप () ठीक है, लेकिन मर्ज () अधिक सीधा-आगे होगा। ध्यान दें कि मर्ज किसी भी वेधशाला के त्रुटि पर बाहर निकल जाएगा, यदि आप बल्कि बाहर निकलें को स्थगित कर देते हैं जब तक कि सभी वेधशालाएं समाप्त नहीं हो जाती हैं, तो आपको मर्जडेलेयर () देखें

एक-एक के लिए, मुझे लगता है कि Observable.concat () स्थिर विधि का उपयोग किया जाना चाहिए। इसके जावदोक इस तरह से कहते हैं:

कॉन्कैट (java.lang.Iterable> क्रम) एक अवलोकन के रूप में वेधशाला के एक Iterable को समतल करते हैं, एक के बाद एक, बिना उन्हें इंटरलेक्ट किए

अगर आप समानांतर निष्पादन नहीं चाहते हैं, तो ऐसा लगता है कि आप क्या कर रहे हैं।

इसके अलावा, अगर आप केवल अपने काम के पूरा होने में रुचि रखते हैं, मान नहीं, तो आप शायद इस पर गौर करना चाहिए completable बजाय प्रत्यक्ष

TLDR: जब वे पूरे हो जाते हैं, तो कार्यों के एक-एक निष्पादन और ऑनकंप्लीमेंट इवेंट के लिए, मुझे लगता है कि कंप्लीटटेबल.कॉनकट () सबसे उपयुक्त है। समानांतर निष्पादन के लिए, Totaltable.merge () या Completable.mergeDelayError () समाधान की तरह लगता है। पहले वाला किसी भी पूर्ण होने पर किसी भी त्रुटि पर तुरंत रोक देगा, बाद वाला उन सभी को निष्पादित करेगा भले ही उनमें से कोई एक त्रुटि हो, और उसके बाद ही त्रुटि की रिपोर्ट करें।


2

आपने संभवतः उस zipऑपरेटर को देखा था जो 2 ऑब्ज़र्वबल्स के साथ काम करता है।

स्थैतिक विधि भी है Observable.zip। इसका एक रूप है जो आपके लिए उपयोगी होना चाहिए:

zip(java.lang.Iterable<? extends Observable<?>> ws, FuncN<? extends R> zipFunction)

आप अधिक के लिए javadoc की जांच कर सकते हैं


2

कोटलिन के साथ

Observable.zip(obs1, obs2, BiFunction { t1 : Boolean, t2:Boolean ->

})

फ़ंक्शन के तर्कों के लिए प्रकार सेट करना महत्वपूर्ण है या आपके पास संकलन त्रुटियां होंगी

अंतिम तर्क प्रकार तर्क की संख्या के साथ बदलता है: 4 के लिए 3 फंक्शन 4 के लिए 2 फंक्शन 3 के लिए बायफ़ंक्शन ...


1

मैं कोटलिन में जावाआरएक्स वेधशालाओं और आरएक्सकोटलिन के साथ कुछ संगणना भारी कोड लिख रहा हूं। मैं पूरी की जाने वाली वेधशालाओं की एक सूची का निरीक्षण करना चाहता हूं और इस बीच मुझे प्रगति और नवीनतम परिणाम के बारे में जानकारी दे रहा हूं। अंत में यह सबसे अच्छा गणना परिणाम देता है। एक अतिरिक्त आवश्यकता मेरे सभी सीपीयू कोर के उपयोग के लिए वेधशालाओं को समानांतर में चलाने की थी। मैं इस समाधान के साथ समाप्त हुआ:

@Volatile var results: MutableList<CalculationResult> = mutableListOf()

fun doALotOfCalculations(listOfCalculations: List<Calculation>): Observable<Pair<String, CalculationResult>> {

    return Observable.create { subscriber ->
        Observable.concatEager(listOfCalculations.map { calculation: Calculation ->
            doCalculation(calculation).subscribeOn(Schedulers.computation()) // function doCalculation returns an Observable with only one result
        }).subscribeBy(
            onNext = {
                results.add(it)
                subscriber.onNext(Pair("A calculation is ready", it))

            },
            onComplete = {
                subscriber.onNext(Pair("Finished: ${results.size}", findBestCalculation(results)) 
                subscriber.onComplete()
            },
            onError = {
                subscriber.onError(it)
            }
        )
    }
}

RxKotlin से परिचित नहीं हैं या @Volatile, लेकिन यह कैसे काम करेगा यदि इसे एक ही समय में कई थ्रेड द्वारा बुलाया जा रहा है? नतीजों का क्या होगा?
ईआईएस

0

मुझे भी ऐसी ही समस्या थी, मुझे हाल ही में किए गए खोज सुझाव को एकीकृत करते हुए आराम कॉल से खोज आइटम लाने की आवश्यकता थी। मैं @MyDogTom समाधान का उपयोग करने की कोशिश कर रहा था, दुर्भाग्य से RxJava में कोई भी अवलोकन योग्य नहीं है। कुछ शोध के बाद मुझे एक समाधान मिला जो मेरे लिए काम करता है।

 fun getSearchedResultsSuggestions(context : Context, query : String) : Single<ArrayList<ArrayList<SearchItem>>>
{
    val fetchedItems = ArrayList<Observable<ArrayList<SearchItem>>>(0)
    fetchedItems.add(fetchSearchSuggestions(context,query).toObservable())
    fetchedItems.add(getSearchResults(query).toObservable())

    return Observable.fromArray(fetchedItems)
        .flatMapIterable { data->data }
        .flatMap {task -> task.observeOn(Schedulers.io())}
        .toList()
        .map { ArrayList(it) }
}

मैंने पर्यवेक्षकों की सरणी से एक अवलोकन योग्य बनाया जिसमें क्वेरी के आधार पर इंटरनेट से सुझावों और परिणामों की सूची शामिल है। उसके बाद आप बस उन कार्यों पर जाएं जिनके लिए flatMapIterable है और उन्हें फ्लैटमैप का उपयोग करके चलाएं, परिणाम को सरणी में रखें, जिसे बाद में रीसायकल दृश्य में लाया जा सकता है।


0

यदि आप प्रोजेक्ट रिएक्टर का उपयोग करते हैं, तो आप उपयोग कर सकते हैं Mono.when

Mono.when(publisher1, publisher2)
.map(i-> {
    System.out.println("everything is done!");
    return i;
}).block()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.