निम्न कोड IllegalArgumentException को प्रत्येक 10-15 प्रयास में समान इनपुट के लिए फेंकता है:

        AllDirectedPaths<Vertex, Edge> allDirectedPaths = new AllDirectedPaths<>(graph);
        List<GraphPath<Vertex, Edge>> paths = allDirectedPaths.getAllPaths(entry, exit, true, null);


        return paths.parallelStream().map(path -> path.getEdgeList().parallelStream()
                .map(edge -> {
                    Vertex source = edge.getSource();
                    Vertex target = edge.getTarget();

                    if (source.containsInstruction(method, instructionIndex)) {
                        return source;
                    } else if (target.containsInstruction(method, instructionIndex)) {
                        return target;
                    } else {
                        return null;
                    }
                }).filter(Objects::nonNull)).findAny().flatMap(Stream::findAny)
                .orElseThrow(() -> new IllegalArgumentException("Given trace refers to no vertex in graph!"));

कोड का विचार एक ऐसे शीर्ष को खोजना है जो एक निश्चित निर्देश को लपेटता है (देखें containsInstruction()), जबकि शीर्ष entry से exit शीर्ष तक कम से कम एक पथ पर है। मुझे पता है कि प्रदर्शन के मामले में कोड इष्टतम नहीं है (पथ पर प्रत्येक मध्यवर्ती शीर्ष दो बार देखा जाता है), लेकिन इससे कोई फर्क नहीं पड़ता।

इनपुट केवल एक ट्रेस (स्ट्रिंग) है जिससे method और instructionIndex निकाले जा सकते हैं। अन्य सभी चर उस अर्थ में निश्चित हैं। इसके अलावा, विधि containsInstruction() का कोई साइड इफेक्ट नहीं है।

क्या इससे कोई फर्क नहीं पड़ता कि 'findAny ()' स्ट्रीम ऑपरेशन कहां रखा जाए? क्या मुझे इसे सीधे फिल्टर ऑपरेशन के बाद रखना चाहिए? या नेस्टेड समानांतर धाराएँ समस्या हैं?

1
auermich 20 नवम्बर 2020, 15:01

1 उत्तर

सबसे बढ़िया उत्तर

आपको .flatMap(path -> ... ) का उपयोग करना चाहिए और .flatMap(Stream::findAny) को हटा देना चाहिए।

आपका कोड काम नहीं करता क्योंकि पहला findAny() एक ऐसी स्ट्रीम देता है जो हमेशा शून्य होती है, लेकिन उसमें null तत्व हो सकते हैं।

फिर, जब आप Optional.flatMap(Stream::findAny) कॉल के माध्यम से दूसरा findAny() लागू करते हैं, तो यह अंतिम खोज ऑपरेशन एक null के साथ समाप्त होने के परिणामस्वरूप एक खाली Optional लौटा सकता है। आंतरिक धारा का तत्व।

इस तरह कोड दिखना चाहिए:

return paths.stream()
    .flatMap(path -> path.getEdgeList().stream()
        .map(edge -> 
             edge.getSource().containsInstruction(method, instructionIndex) ?
             edge.getSource()                                               :
             edge.getTarget().containsInstruction(method, instructionIndex) ?
             edge.getTarget()                                               :
             null)
        .filter(Objects::nonNull))
    .findAny()
    .orElseThrow(() -> new IllegalArgumentException("whatever"));

एक तरफ ध्यान दें: समानांतर धाराएँ क्यों? आपकी पाइपलाइन में CPU बाध्य कार्य प्रतीत नहीं होते हैं। इसके अलावा, समानांतर धाराएँ बहुत अधिक उपरि बनाती हैं। वे बहुत कम परिदृश्यों में उपयोगी होते हैं, यानी हजारों तत्वों और पाइपलाइन के साथ गहन सीपीयू संचालन


संपादित करें: जैसा कि टिप्पणियों में सुझाया गया है, आंतरिक स्ट्रीम के map और filter संचालन को सुरक्षित रूप से बाहरी स्ट्रीम में ले जाया जा सकता है। इस तरह, पठनीयता में सुधार होता है और प्रदर्शन-वार कोई अंतर नहीं होता है:

return paths.stream()
    .flatMap(path -> path.getEdgeList().stream())
    .map(edge -> 
         edge.getSource().containsInstruction(method, instructionIndex) ?
         edge.getSource()                                               :
         edge.getTarget().containsInstruction(method, instructionIndex) ?
         edge.getTarget()                                               :
         null)
    .filter(Objects::nonNull)
    .findAny()
    .orElseThrow(() -> new IllegalArgumentException("whatever"));

एक और नोट: शायद map के अंदर कोड को Edge वर्ग की एक विधि में दोबारा सुधारना बेहतर होगा, ताकि स्रोत, लक्ष्य या null को वापस करने का तर्क कक्षा में हो जिसके पास पहले से ही सारी जानकारी है।

1
fps 20 नवम्बर 2020, 20:29