Làm thế nào để đảm bảo thứ tự xử lý trong luồng java8?


148

Tôi muốn xử lý danh sách bên trong một XMLđối tượng java. Tôi phải đảm bảo xử lý tất cả các yếu tố để tôi nhận được chúng.

Do đó tôi có nên gọi sequentialmỗi streamtôi sử dụng không? list.stream().sequential().filter().forEach()

Hoặc nó chỉ đủ để sử dụng luồng miễn là tôi không sử dụng song song? list.stream().filter().forEach()

Câu trả lời:


338

Bạn đang hỏi sai câu hỏi. Bạn đang hỏi về sequentialso với paralleltrong khi bạn muốn xử lý các mục theo thứ tự , vì vậy bạn phải hỏi về việc đặt hàng . Nếu bạn có một luồng được đặt hàng và thực hiện các hoạt động đảm bảo duy trì trật tự, thì luồng đó được xử lý song song hay tuần tự; việc thực hiện sẽ duy trì trật tự.

Các thuộc tính được đặt hàng là khác biệt so với song song và tuần tự. Ví dụ: nếu bạn gọi stream()trên một HashSetluồng sẽ không được sắp xếp trong khi gọi stream()trên Listtrả về một luồng đã ra lệnh. Lưu ý rằng bạn có thể gọi unordered()để giải phóng hợp đồng đặt hàng và có khả năng tăng hiệu suất. Một khi luồng không có thứ tự, không có cách nào để thiết lập lại thứ tự. (Cách duy nhất để biến một luồng không có thứ tự thành một thứ tự là gọi sorted, tuy nhiên, thứ tự kết quả không nhất thiết phải là thứ tự ban đầu).

Xem thêm phần Đặt hàng trên mạng của java.util.streamtài liệu gói .

Để đảm bảo duy trì trật tự trong toàn bộ hoạt động luồng, bạn phải nghiên cứu tài liệu về nguồn của luồng, tất cả các hoạt động trung gian và hoạt động của thiết bị đầu cuối để xem chúng có duy trì đơn hàng hay không (hoặc liệu nguồn có đặt hàng trước không địa điểm).

Điều này có thể rất tinh tế, ví dụ: Stream.iterate(T,UnaryOperator)tạo một luồng có thứ tự trong khi Stream.generate(Supplier)tạo ra một luồng không có thứ tự . Lưu ý rằng bạn cũng đã mắc một lỗi phổ biến trong câu hỏi của mình vì không duy trì việc đặt hàng. Bạn phải sử dụng nếu bạn muốn xử lý các phần tử của luồng theo thứ tự được bảo đảm.forEach forEachOrdered

Vì vậy, nếu listcâu hỏi của bạn thực sự là a java.util.List, stream()phương thức của nó sẽ trả về một luồng được đặt hàngfiltersẽ không thay đổi thứ tự. Vì vậy, nếu bạn gọi list.stream().filter() .forEachOrdered(), tất cả các phần tử sẽ được xử lý tuần tự theo thứ tự, trong khi đối với list.parallelStream().filter().forEachOrdered()các phần tử có thể được xử lý song song (ví dụ: bằng bộ lọc) nhưng hành động cuối sẽ vẫn được gọi theo thứ tự (rõ ràng sẽ làm giảm lợi ích của việc thực thi song song) .

Nếu bạn, ví dụ, sử dụng một hoạt động như

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

toàn bộ hoạt động có thể được hưởng lợi từ việc thực hiện song song nhưng danh sách kết quả sẽ luôn theo đúng thứ tự, bất kể bạn sử dụng luồng song song hay tuần tự.


48
Vâng, câu trả lời tốt. Một điều mà tôi đã tìm thấy là thuật ngữ chúng tôi sử dụng, ít nhất là bằng tiếng Anh, chẳng hạn như "trước", "sau", v.v., khá mơ hồ. Có hai loại thứ tự ở đây: 1) thứ tự gặp gỡ (còn được gọi là thứ tự không gian ) và 2) thứ tự xử lý (còn được gọi là thứ tự thời gian ). Với sự khác biệt này, có thể hữu ích khi sử dụng các từ như "bên trái" hoặc "bên phải" khi thảo luận về thứ tự gặp gỡ và "sớm hơn" hoặc "muộn hơn" khi thảo luận về thứ tự xử lý.
Stuart Marks

Tôi hiểu List<>sẽ giữ gìn trật tự, nhưng sẽ Collection<>thế nào?
Josh C.

5
@JoshC. nó phụ thuộc vào loại bộ sưu tập thực tế. Sets thường không, trừ khi nó là một SortedSethoặc LinkedHashSet. Các chế độ xem bộ sưu tập của một Map( keySet(), entrySet()values()) kế thừa Mapchính sách của, tức là được sắp xếp khi bản đồ là một SortedMaphoặc LinkedHashMap. Hành vi được xác định bởi các đặc điểm được báo cáo bởi bộ chia của bộ sưu tập . Việc defaultthực hiện Collectionkhông báo cáo các ORDEREDđặc tính, vì vậy nó không được sắp xếp, trừ khi bị ghi đè.
Holger

@Holger Tôi có một câu hỏi có thể liên quan phần nào đến một phần nhỏ trong câu trả lời của bạn.
Naman

1
Đáng chú ý là forEachOrderedchỉ khác với forEachkhi sử dụng các luồng song song - nhưng thực tế tốt để sử dụng nó dù sao khi đặt hàng có vấn đề trong trường hợp phương pháp hấp bao giờ thay đổi ...
Steve Chambers

0

Tóm lại:

Thứ tự phụ thuộc vào cấu trúc dữ liệu nguồn và các hoạt động luồng trung gian. Giả sử bạn đang sử dụng một Listquá trình xử lý nên được đặt hàng (vì filtersẽ không thay đổi trình tự ở đây).

Thêm chi tiết:

Tuần tự vs Song song với Không sắp xếp:

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.

Đặt hàng trực tuyến:

Javadocs

Các luồng có thể có hoặc không có thứ tự bắt gặp được xác định. Việc một luồng có thứ tự gặp hay không phụ thuộc vào nguồn và các hoạt động trung gian. Một số nguồn phát nhất định (như Danh sách hoặc mảng) về bản chất được sắp xếp theo thứ tự, trong khi các nguồn khác (như Hashset) thì không. Một số hoạt động trung gian, chẳng hạn như sort (), có thể áp đặt thứ tự bắt gặp đối với luồng không được sắp xếp khác và các hoạt động khác có thể khiến luồng được sắp xếp không theo thứ tự, chẳng hạn như BaseStream.unordered (). Hơn nữa, một số hoạt động của thiết bị đầu cuối có thể bỏ qua thứ tự gặp phải, chẳng hạn như forEach ().

Nếu một luồng được sắp xếp, hầu hết các hoạt động bị hạn chế hoạt động trên các phần tử theo thứ tự gặp gỡ của chúng; nếu nguồn của luồng là Danh sách chứa [1, 2, 3], thì kết quả thực hiện bản đồ (x -> x * 2) phải là [2, 4, 6]. Tuy nhiên, nếu nguồn không có thứ tự bắt gặp được xác định, thì mọi hoán vị của các giá trị [2, 4, 6] sẽ là kết quả hợp lệ.

Đối với các luồng liên tiếp, sự hiện diện hoặc vắng mặt của lệnh gặp gỡ không ảnh hưởng đến hiệu suất, chỉ mang tính quyết định. Nếu một luồng được ra lệnh, việc thực hiện lặp lại các đường ống giống hệt nhau trên một nguồn giống hệt nhau sẽ tạo ra kết quả giống hệt nhau; nếu nó không được ra lệnh, việc thực hiện lặp đi lặp lại có thể tạo ra các kết quả khác nhau.

Đối với các luồng song song, việc nới lỏng các ràng buộc đặt hàng đôi khi có thể cho phép thực thi hiệu quả hơn. Một số thao tác tổng hợp nhất định, chẳng hạn như lọc trùng lặp (tách biệt ()) hoặc giảm nhóm (Collector.groupingBy ()) có thể được thực hiện hiệu quả hơn nếu việc sắp xếp các phần tử không liên quan. Tương tự, các hoạt động gắn liền với trật tự gặp phải, chẳng hạn như giới hạn (), có thể yêu cầu bộ đệm để đảm bảo trật tự đúng, làm giảm lợi ích của việc xử lý song song. Trong trường hợp luồng có thứ tự gặp gỡ, nhưng người dùng không đặc biệt quan tâm đến thứ tự gặp gỡ đó, việc hủy thứ tự rõ ràng với luồng không có thứ tự () có thể cải thiện hiệu suất song song cho một số hoạt động trạng thái hoặc đầu cuối. Tuy nhiên, hầu hết các đường ống dòng, chẳng hạn như ví dụ "tổng trọng lượng của các khối" ở trên,

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.