Database
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Database

Luồng tuần tự so với Luồng song song trong Java là gì?

Java có thể song song hóa các hoạt động dòng để tận dụng các hệ thống đa lõi. Bài viết này cung cấp quan điểm và chỉ ra cách dòng song song có thể cải thiện hiệu suất với các ví dụ thích hợp.

Luồng trong Java

Đ ường truyền trong Java là một chuỗi các đối tượng được biểu diễn như một đường dẫn dữ liệu. Nó thường có một nguồn nơi chứa dữ liệu và một điểm đến nơi nó được truyền đi. Lưu ý rằng một luồng không phải là một kho lưu trữ; thay vào đó, nó hoạt động trên một nguồn dữ liệu chẳng hạn như trên một mảng hoặc một tập hợp. Các bit ở giữa trong đoạn văn thực sự được gọi là dòng. Trong quá trình truyền, luồng thường trải qua một hoặc nhiều phép biến đổi có thể xảy ra, chẳng hạn như lọc hoặc sắp xếp, hoặc nó có thể là bất kỳ quá trình nào khác hoạt động trên dữ liệu. Điều này tùy chỉnh dữ liệu ban đầu thành một dạng khác, thông thường, theo nhu cầu của người lập trình. Do đó, một luồng mới được tạo theo thao tác được áp dụng trên đó. Ví dụ:khi một luồng được sắp xếp, nó dẫn đến một luồng mới tạo ra một kết quả sau đó được sắp xếp. Điều này có nghĩa là dữ liệu mới là bản sao được biến đổi của bản gốc thay vì ở dạng ban đầu.

Luồng tuần tự

Bất kỳ hoạt động luồng nào trong Java, trừ khi được chỉ định rõ ràng là song song, đều được xử lý tuần tự. Về cơ bản chúng là các luồng không song song được sử dụng một luồng duy nhất để xử lý đường ống của chúng. Các luồng tuần tự không bao giờ tận dụng được lợi thế của hệ thống đa lõi ngay cả khi hệ thống bên dưới có thể hỗ trợ thực thi song song. Ví dụ:điều gì xảy ra khi chúng tôi áp dụng đa luồng để xử lý luồng? Thậm chí sau đó, nó hoạt động trên một lõi duy nhất tại một thời điểm. Tuy nhiên, nó có thể nhảy từ lõi này sang lõi khác trừ khi được ghim rõ ràng vào một lõi cụ thể. Ví dụ:xử lý trong bốn luồng khác nhau so với bốn lõi khác nhau rõ ràng là khác nhau, nơi cái trước không phù hợp với cái sau. Hoàn toàn có thể thực thi nhiều luồng trong một môi trường lõi đơn nhưng xử lý song song hoàn toàn là một thể loại khác. Một chương trình cần được thiết kế nền tảng để lập trình song song ngoài việc thực thi trong môi trường hỗ trợ nó. Đây là lý do tại sao lập trình song song là một lĩnh vực phức tạp.

Hãy thử một ví dụ để minh họa thêm cho ý tưởng này.

package org.mano.example;

import java.util.Arrays;
import java.util.List;

public class Main2 {
   public static oid main(String[] args) {
      List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9);
      list.stream().forEach(System.out::println);
      System.out.println();
      list.parallelStream().forEach(System.out::println);
   }
}

Đầu ra

123456789
685973214

Ví dụ này là một minh họa của q luồng tuần tự cũng như q luồng song song đang hoạt động. list.stream () hoạt động theo trình tự trên một chuỗi đơn với println () hoạt động. list.parallelStream () , mặt khác, được xử lý song song, tận dụng tối đa môi trường đa nhân bên dưới. Khía cạnh thú vị nằm trong đầu ra của chương trình trước đó. Trong trường hợp dòng tuần tự, nội dung của danh sách được in theo một trình tự có thứ tự. Mặt khác, đầu ra của luồng song song không có thứ tự và trình tự thay đổi mỗi khi chương trình được chạy. Điều này biểu thị ít nhất một điều:đó là lời gọi của list.parallelStream () phương pháp làm cho println câu lệnh hoạt động trong nhiều chuỗi, cái gì đó list.stream () thực hiện trong một chuỗi duy nhất.

Luồng song song

Động cơ chính đằng sau việc sử dụng một luồng song song là làm cho quá trình xử lý luồng trở thành một phần của chương trình song song, ngay cả khi toàn bộ chương trình có thể không được song song hóa. Dòng song song tận dụng các bộ xử lý đa lõi, dẫn đến hiệu suất tăng đáng kể. Không giống như bất kỳ lập trình song song nào, chúng rất phức tạp và dễ xảy ra lỗi. Tuy nhiên, thư viện dòng Java cung cấp khả năng thực hiện điều đó một cách dễ dàng và đáng tin cậy. Toàn bộ chương trình có thể không được chạy song song. nhưng ít nhất phần xử lý luồng có thể được song song hóa. Chúng thực sự khá đơn giản theo nghĩa là chúng ta có thể gọi một vài phương thức và phần còn lại sẽ được xử lý. Có một số cách để làm điều đó. Một trong những cách như vậy là để có được một luồng song song bằng cách gọi llelStream () phương pháp được xác định bởi Bộ sưu tập . Một cách khác là gọi song song () phương pháp được xác định bởi BaseStream trên một luồng tuần tự. Luồng tuần tự được song song hóa bởi lời gọi. Lưu ý rằng nền tảng bên dưới phải hỗ trợ lập trình song song, chẳng hạn như với hệ thống đa lõi. Nếu không, không có ích lợi gì trong lời kêu gọi. Luồng sẽ được xử lý theo trình tự trong trường hợp như vậy, ngay cả khi chúng ta đã thực hiện lệnh gọi. Nếu lời gọi được thực hiện trên một luồng đã song song, nó sẽ không làm gì cả và chỉ trả về luồng.

Để đảm bảo rằng kết quả của quá trình xử lý song song được áp dụng trên luồng giống như kết quả thu được thông qua xử lý tuần tự, các luồng song song phải không trạng thái, không can thiệp và liên kết.

Một ví dụ nhanh

package org.mano.example;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Main {

   public static void main(String[] args) {
      List<Employee> employees = Arrays.asList(
         new Employee(1276, "FFF",2000.00),
         new Employee(7865, "AAA",1200.00),
         new Employee(4975, "DDD",3000.00),
         new Employee(4499, "CCC",1500.00),
         new Employee(9937, "GGG",2800.00),
         new Employee(5634, "HHH",1100.00),
         new Employee(9276, "BBB",3200.00),
         new Employee(6852, "EEE",3400.00));

      System.out.println("Original List");
      printList(employees);

      // Using sequential stream
      long start = System.currentTimeMillis();
      List<Employee> sortedItems = employees.stream()
         .sorted(Comparator
            .comparing(Employee::getName))
         .collect(Collectors.toList());
      long end = System.currentTimeMillis();

      System.out.println("sorted using sequential stream");
      printList(sortedItems);
      System.out.println("Total the time taken process :"
         + (end - start) + " milisec.");

      // Using parallel stream
      start = System.currentTimeMillis();
      List<Employee> anotherSortedItems = employees
         .parallelStream().sorted(Comparator
            .comparing(Employee::getName))
         .collect(Collectors.toList());
      end = System.currentTimeMillis();

      System.out.println("sorted using parallel stream");
      printList(anotherSortedItems);
      System.out.println("Total the time taken process :"
         + (end - start) + " milisec.");


      double totsal=employees.parallelStream()
         .map(e->e.getSalary())
         .reduce(0.00,(a1,a2)->a1+a2);
      System.out.println("Total Salary expense: "+totsal);
      Optional<Employee> maxSal=employees.parallelStream()
         .reduce((Employee e1, Employee e2)->
         e1.getSalary()<e2.getSalary()?e2:e1);
      if(maxSal.isPresent())
         System.out.println(maxSal.get().toString());
   }

   public static void printList(List<Employee> list) {
      for (Employee e : list)
         System.out.println(e.toString());
   }
}


package org.mano.example;

public class Employee {
   private int empid;
   private String name;
   private double salary;

   public Employee() {
      super();
   }

   public Employee(int empid, String name,
         double salary) {
      super();
      this.empid = empid;
      this.name = name;
      this.salary = salary;
   }

   public int getEmpid() {
      return empid;
   }

   public void setEmpid(int empid) {
      this.empid = empid;
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   public double getSalary() {
      return salary;
   }

   public void setSalary(double salary) {
      this.salary = salary;
   }

   @Override
   public String toString() {
      return "Employee [empid=" + empid + ", name="
         + name + ", salary=" + salary + "]";
   }
}

Trong đoạn mã trước, hãy lưu ý cách chúng tôi đã áp dụng sắp xếp trên một luồng bằng cách sử dụng thực thi tuần tự.

List<Employee> sortedItems = employees.stream()
               .sorted(Comparator
               .comparing(Employee::getName))
               .collect(Collectors.toList());

và thực thi song song đạt được bằng cách thay đổi mã một chút.

List<Employee> anotherSortedItems = employees
               .parallelStream().sorted(Comparator
               .comparing(Employee::getName))
               .collect(Collectors.toList());

Chúng tôi cũng sẽ so sánh thời gian của hệ thống để biết phần nào của mã cần nhiều thời gian hơn. Hoạt động song song bắt đầu sau khi luồng song song được song song () thu được một cách rõ ràng phương pháp. Có một phương pháp thú vị khác, được gọi là Reduce () . Khi chúng tôi áp dụng phương pháp này cho một luồng song song, hoạt động có thể xảy ra trong các luồng khác nhau.

Tuy nhiên, chúng ta luôn có thể chuyển đổi giữa song song và tuần tự theo nhu cầu. Nếu chúng tôi muốn thay đổi luồng song song thành dòng tuần tự, chúng tôi có thể làm như vậy bằng cách gọi sequential () phương pháp được chỉ định bởi BaseStream . Như chúng ta đã thấy trong chương trình đầu tiên của mình, hoạt động được thực hiện trên luồng có thể có thứ tự hoặc không theo thứ tự theo thứ tự của các phần tử. Điều này có nghĩa là thứ tự phụ thuộc vào nguồn dữ liệu. Tuy nhiên, đây không phải là tình huống xảy ra trong trường hợp các luồng song song. Để tăng hiệu suất, chúng được xử lý song song. Bởi vì điều này được thực hiện mà không có bất kỳ trình tự nào, trong đó mỗi phân vùng của luồng được xử lý độc lập với các phân vùng khác mà không có bất kỳ sự phối hợp nào, hậu quả là không thể đoán trước được thứ tự. Tuy nhiên, nếu chúng ta muốn thực hiện cụ thể một thao tác trên từng phần tử trong luồng song song được sắp xếp, chúng ta có thể xem xét forEachOrdered () , là một phương thức thay thế cho forEach () phương pháp.

Kết luận

Các API luồng đã là một phần của Java từ lâu, nhưng việc bổ sung các tinh chỉnh của xử lý song song là rất đáng hoan nghênh, đồng thời là một tính năng khá hấp dẫn. Điều này đặc biệt đúng bởi vì máy móc hiện đại là đa lõi và có một sự kỳ thị rằng thiết kế lập trình song song rất phức tạp. Các API do Java cung cấp cung cấp khả năng kết hợp một số chỉnh sửa lập trình song song trong một chương trình Java có thiết kế tổng thể về thực thi tuần tự. Đây có lẽ là phần tốt nhất của tính năng này.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Kết nối Talend trên Windows với Cơ sở dữ liệu ODBC

  2. Xem xét Hiệu suất Ảnh chụp Cơ sở dữ liệu

  3. Làm thế nào để tính toán tổng số chạy trong Redshift

  4. Kiểm tra tự động ứng dụng dành cho máy tính để bàn:tổng quan về tính hiệu quả và các khuôn khổ

  5. SCD loại 4