Java8 akışlarında işlem sırası nasıl sağlanır?


153

Listeleri bir XMLjava nesnesi içinde işlemek istiyorum . Tüm öğelerin elime ulaşması için işlendiğinden emin olmalıyım.

Bu nedenle sequential, streamkullandığım her birini aramalı mıyım ? list.stream().sequential().filter().forEach()

Ya da paralelliği kullanmadığım sürece akışı kullanmak yeterli mi? list.stream().filter().forEach()

Yanıtlar:


359

Yanlış soruyu soruyorsunuz. Sorduğunuz sequentialvs. parallelEğer süreç öğeleri istediğiniz oysa sırayla size sormak zorunda, sipariş . Bir varsa sipariş akışını ve düzenini korumak garanti işlemleri gerçekleştirmek, bunun önemi akışı paralel veya ardışık işlenmiş olup olmadığını yapar; uygulama düzeni koruyacaktır.

Sıralı özellik, paralel ve sıralı özelliklerden farklıdır. Eğer ararsanız Örneğin stream()bir üzerinde HashSetarama sırasında dere sırasız olacak stream()bir üzerinde Listgetiri sıralı akışı. unordered()Sipariş sözleşmesini iptal etmek ve potansiyel olarak performansı artırmak için arayabileceğinizi unutmayın . Akışın sıralaması olmadığında sıralamayı yeniden kurmanın bir yolu yoktur. (Sıralanmamış bir akışı sıralı hale getirmenin tek yolu çağırmaktır sorted, ancak sonuçta ortaya çıkan sıra mutlaka orijinal sıra olmayabilir).

Ayrıca bkz “Talimat” bölümüne ait java.util.streampaket belgelerine .

Tüm akış operasyonu boyunca siparişin sürdürülmesini sağlamak için, akışın kaynağının, tüm ara operasyonların ve terminal operasyonunun, siparişi koruyup korumadıklarını (veya kaynağın ilk sırada bir siparişe sahip olup olmadığını) incelemeniz gerekir. yer).

Bu çok ince olabilir, örneğin Stream.iterate(T,UnaryOperator)sıralı bir akış Stream.generate(Supplier)oluştururken sırasız bir akış oluşturur . Olarak ayrıca söz konusu ortak hata yaptığını Not gelmez sipariş koruyun. Akışın öğelerini garantili bir sırayla işlemek istiyorsanız kullanmanız gerekir.forEach forEachOrdered

Bu nedenle list, sorunuz gerçekten bir java.util.Listise, stream()yöntemi sıralı bir akış döndürür filterve sıralamayı değiştirmez. Bu nedenle, çağırırsanız list.stream().filter() .forEachOrdered(), tüm öğeler sırayla işlenecektir, oysa list.parallelStream().filter().forEachOrdered()öğeler paralel olarak işlenebilir (örneğin filtre tarafından) ancak uç eylem yine de sırayla çağrılacaktır (bu açıkça paralel yürütmenin faydasını azaltacaktır) .

Örneğin, aşağıdaki gibi bir işlem kullanırsanız

List<…> result=inputList.parallelStream().map(…).filter(…).collect(Collectors.toList());

tüm işlem paralel yürütmeden faydalanabilir, ancak ortaya çıkan liste, paralel veya sıralı akış kullanıp kullanmadığınıza bakılmaksızın her zaman doğru sırada olacaktır.


48
Evet, güzel cevap. Bulduğum bir şey, en azından İngilizce'de kullandığımız terminolojinin, örneğin "önce", "sonra" ve benzeri, oldukça belirsiz olduğudur. Burada iki tür sıralama vardır: 1) karşılaşma sırası ( uzaysal düzen olarak da bilinir ) ve 2) işleme sırası ( zamansal düzen olarak da bilinir ). Bu ayrım akılda tutularak, karşılaşma sırasını tartışırken "sol" veya "sağda" ve işleme sırasını tartışırken "daha önce" veya "daha sonra" gibi kelimeleri kullanmak faydalı olabilir.
Stuart Marks

6
@JoshC. gerçek toplama türüne bağlıdır. Seta SortedSetveya olmadığı sürece s genellikle yapmaz LinkedHashSet. Bir Map( keySet(), entrySet()ve values()) Mapöğesinin koleksiyon görünümleri, politikasını devralır , yani harita bir SortedMapveya olduğunda sıralanır LinkedHashMap. Davranış, koleksiyonun ayırıcısı tarafından bildirilen özelliklere göre belirlenir . defaultUygulanması Collectionbildirmez ORDEREDgeçersiz sürece, sırasız yüzden, karakteristik.
Holger

1
Bunun forEachOrderedyalnızca forEachparalel akışları kullanırken farklılık gösterdiğini belirtmek gerekir - ancak buharlama yönteminin değişmesi durumunda sipariş verirken yine de kullanmak iyi bir uygulamadır ...
Steve Chambers

1
@Rafael o sayfadaki hangi örneği kastediyorsunuz?
Holger

1
@Rafael çıktının önünde " Aşağıdakine benzer çıktı yazdırır :" ifadesi gelir; bu, "3 4 1 6 2 5 7 8" listenin sırasına uymayan herhangi bir olası çıktı için örnek niteliğinde olduğu anlamına gelir (8 7 6 5 4 3 2 1).
Holger

0

Kısaca:

Sıralama, kaynak veri yapısına ve ara akış işlemlerine bağlıdır. Bir Listişleme kullandığınızı varsayarsak , işlemin sipariş edilmesi gerekir (çünkü filterburadaki sırayı değiştirmeyecektir).

Daha fazla detay:

Sıralı - Paralel - Sırasız:

Javadocs

S sequential()
Returns an equivalent stream that is sequential. May return itself, either because the stream was already sequential, or because the underlying stream state was modified to be sequential.
This is an intermediate operation.
S parallel()
Returns an equivalent stream that is parallel. May return itself, either because the stream was already parallel, or because the underlying stream state was modified to be parallel.
This is an intermediate operation.
S unordered()
Returns an equivalent stream that is unordered. May return itself, either because the stream was already unordered, or because the underlying stream state was modified to be unordered.
This is an intermediate operation.

Akış Sıralaması:

Javadocs

Akışların tanımlanmış bir karşılaşma sırası olabilir veya olmayabilir. Bir akışın karşılaşma sırasına sahip olup olmadığı, kaynağa ve ara işlemlere bağlıdır. Bazı akış kaynakları (Liste veya diziler gibi) içsel olarak sıralanır, ancak diğerleri (HashSet gibi) değildir. Sıralanmış () gibi bazı ara işlemler, aksi takdirde sıralanmamış bir akışa bir karşılaşma sırası uygulayabilir ve diğerleri, BaseStream.unordered () gibi sıralı bir akışı sırasız hale getirebilir. Ayrıca, forEach () gibi bazı uçbirim işlemleri karşılaşma sırasını göz ardı edebilir.

Bir akış sıralanırsa, çoğu işlem, karşılaşma sıralarındaki öğeler üzerinde çalışmak üzere sınırlandırılır; akışın kaynağı [1, 2, 3] içeren bir Liste ise, eşlemenin çalıştırılmasının sonucu (x -> x * 2) [2, 4, 6] olmalıdır. Bununla birlikte, kaynağın tanımlanmış bir karşılaşma sırası yoksa, [2, 4, 6] değerlerinin herhangi bir permütasyonu geçerli bir sonuç olacaktır.

Sıralı akışlar için, bir karşılaşma sırasının varlığı veya yokluğu performansı etkilemez, yalnızca determinizmi etkiler. Bir akış sipariş edilirse, özdeş bir kaynak üzerinde aynı akış boru hatlarının tekrar tekrar yürütülmesi aynı sonucu verecektir; sipariş edilmediği takdirde, tekrarlanan uygulama farklı sonuçlar doğurabilir.

Paralel akışlar için, sıralama kısıtlamasını gevşetmek bazen daha verimli yürütmeyi sağlayabilir. Yinelenenlerin filtrelenmesi (farklı ()) veya gruplandırılmış indirgeme (Collectors.groupingBy ()) gibi belirli toplu işlemler, öğelerin sıralanmasıyla alakalı değilse daha verimli bir şekilde uygulanabilir. Benzer şekilde, limit () gibi sırayla karşılaşmaya özünde bağlı olan işlemler, paralelliğin yararını zayıflatarak düzgün sıralamayı sağlamak için arabelleğe almayı gerektirebilir. Akışın bir karşılaşma sırasına sahip olduğu, ancak kullanıcının bu karşılaşma sırasını özellikle önemsemediği durumlarda, akışın sırasız () ile açıkça sırasının kaldırılması, bazı durum bilgisi olan veya uçbirim işlemleri için paralel performansı artırabilir. Bununla birlikte, yukarıdaki "blokların ağırlıklarının toplamı" örneği gibi çoğu akış hattı,

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.