Java에서 Lambda 표현식 병렬 및 조합 동작

7477 단어 javalambda표현식
직렬에서 병렬로
직렬은 한 단계씩 처리하는 것을 가리킨다. 즉, 일반적인 상황에서 코드가 한 줄씩 실행되는 것이다.
만약 우리가 자주 사용하는 교체기식 순환을 전개한다면 순환체 내에서 정의된 조작을 직렬로 실행하는 것이다.

sum += arr.get(0);
sum += arr.get(1);
sum += arr.get(2);
//...
책의 처음부터 Java는 집합을 지원하는 병렬 계산이 필요하다고 언급했다(그리고 Lambda는 이 요구에 가능성을 제공했다).
이러한 기능은 모두 라이브러리 코드에서 실현될 것이며 우리 사용자에게 병행을 실현하는 복잡성은 크게 낮아질 것이다(최소한의 경우 관련 방법만 호출해야 한다).
또한 병발과 병행이라는 두 개념은 사실 다르다. 모르면 스스로 알아라. 여기서 유행하는 말 한마디만 인용한다.
하나는 코드 구조에 관한 것이고, 하나는 코드 실행에 관한 것이다.
만약 우리가 계산 임무를 CPU의 네 개의 코어에 고르게 분배하고 싶다면, 우리는 모든 코어에 계산에 사용되는 루트를 분배하고, 모든 루트에서 전체 임무의 하위 임무를 진행할 것이다.
책에는 매우 형상적인 위조 코드가 있다.

if the task list contains more than N/4 elements {
 leftTask = task.getLeftHalf()
 rightTask = task.getRightHalf()
 doInparallel {
 leftResult = leftTask.solve()
 rightResult = rightTask.solve()
 }
 result = combine(leftResult, rightResult)
} else {
 result = task.solveSequentially()
}
코드에서 네 개의 작업 요소를 한 조로 나누어 네 개의 내부 핵으로 병행 처리한 다음에 두 조로 한 번씩 결과를 합쳐서 전체 작업 대기열의 최종 결과를 얻는다.
전체적인 처리 프로세스를 보면 먼저 작업 대기열을 그룹화하고 각 그룹을 병행 처리한 다음에 결과를 그룹화하여 합병한다(합병은 파이프를 통해 작업을 종료한다).
Java8 이전에 개발자들은 집합을 위한 fork/join 프레임워크를 사용하여 이 모델을 실현했다.
그러나 이제 코드에 대한 성능 최적화는 매우 쉬운 일이다.
우리가 지난 절에서 얻은 최종 코드를 기억하고 있다.

long validContactCounter = contactList.stream()
 .map(s -> new Contact().setName(s))
 .filter(Contact::call)
 .count();
변경 사항:

long validContactCounter = contactList.parallelStream()
 .map(s -> new Contact().setName(s))
 .filter(Contact::call)
 .count();
stream()이 parallelStream()으로 변경됨 주의()
또한 다음 그림은 상술한 임무를 네 개의 검사에 따라 분해 처리하여 최종적으로 결과를 합병하고 파이프를 종료하는 방법을 보여 줍니다.
반복 분해의 목적은 하위 임무들이 직렬로 실행될 수 있도록 하는 것이다.
조합 행위
Java 작성자는 Java에 순수한'함수'는 존재하지 않고'방법'만 존재한다는 것을 알아야 한다.즉, 자바의 함수는 특정한 클래스에 의존하거나 클래스의 특정한 행위로 존재해야 한다.
다른 언어에서는 CoffeeScript 구문으로 하나의 함수를 설명하는 순수한 함수가 존재합니다.

eat = (x) -> 
 alert("#{x} has been eatten!")
이런 작법은 람다 표현식의 문법과 매우 가깝다. 즉, 익명 내부류에 비해 람다 표현식은 일종의 함수 표현식처럼 보인다.
함수에 대해 하나의 핵심 조작은 바로 조합이다.만약 일원 2차 함수 중 하나가 sqrt(sqr(b)-4*a*c)를 풀 것을 요구한다면 여러 개의 하위 함수를 조합한 것이다.
대상을 향해 우리는 결합을 해체하는 방식으로 그것을 분해하고, 마찬가지로 우리도 이런 방식으로 함수 행위를 분해하기를 바란다.
우선, 이전 두 절에서 사용한 예를 따라 Contact 클래스를 약간 수정하고name 속성을 이름과 성으로 나눈다.

private String firstName;
private String lastName;
만약 우리가 지금 연락처를 정렬하려고 한다면, 사용자 정의 정렬을 만드는 Java 표준 방식은 Comparator를 만드는 것이다.

public interface Comparator<T> {
 int compare(T o1, T o2);
 //...
}
우리는 연락처를 정렬하기 위해 비교명의 이니셜을 사용하고 싶다.

Comparator<Contact> byFirstName = new Comparator<Contact>() {
 @Override
 public int compare(Contact o1, Contact o2) {
 return Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));
 }
};
Lambda 작법:

Comparator<Contact> byFirstNameLambdaForm = (o1, o2) ->
 Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));
이 코드를 작성한 후 IDEA는 즉시 코드를 Comparator로 바꿀 수 있음을 알려 주었습니다.comparingInt(...),그러나 이것은 뒷말이니 잠시 내버려 두지 않겠다.
위의 코드에서 우리는 조합 행위, 즉 Comparator<Contact>의compare (...) 를 발견했다방법에는 o.getFirstName () 과 Character가 함께 사용됩니다.compare(...)이 두 가지 방법(간결을 위해charAt(...)은 잠시 고려하지 않습니다.자바에 있어요.util.function에서 우리는 이런 함수의 원형을 찾았다.

public interface Function<T, R> {
 R apply(T t);
 //...
}
T 유형의 매개변수를 수신하여 R 유형의 결과를 반환합니다.
이제 "비교명의 이니셜"이라는 비교 키의 추출 동작을 함수 대상의 실례로 추출합니다.

Function<Contact, Character> keyExtractor = o -> o.getFirstName().charAt(0);
그리고'비교 이니셜'이라는 구체적인 비교 행위를 추출한다.

Comparator<Character> keyComparator = (c1, c2) -> Character.compare(c1, c2);
keyExtractor와 keyComparator가 있으면 Comparator를 다시 어셈블합니다.

Comparator<Contact> byFirstNameAdvanced = (o1, o2) ->
 keyComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2));
이 단계에 이르러 우리는 간결성을 희생했지만 상응하는 유연성을 얻었다. 즉, 비교 키를 이름이 아닌 성으로 바꾸면 keyExtractor를 다음과 같이 바꾸면 된다.

Function<Contact, Character> keyExtractor = o -> o.getLastName().charAt(0);
다행히도 라이브러리 디자이너는 이러한 자연 비교의 수요의 보편성을 고려하여 Comparator 인터페이스에 정적 방법인comparing(...)을 제공했다.비교 키의 추출 규칙만 입력하면 해당 키에 해당하는 Comparator를 생성할 수 있습니다. 신기하지 않습니까?

Comparator<Contact> compareByFirstName = Comparator.comparing(keyExtractor);
연락처의 성과 이름의 길이를 비교하는 것과 같은 비교 규칙을 바꾸고 싶어도 약간의 변경만 하면 된다.

Comparator<Contact> compareByNameLength = Comparator.comparing(p -> (p.getFirstName() + p.getLastName()).length());
이것은 우리가 주목하는 초점을 실제적으로 비교하는 규칙에 집중시키는 중대한 개선이다. 필요한 풀 코드를 대량으로 구축하는 것이 아니라.
comparing(...)간단한 행위를 받아들여 이 행위를 바탕으로 더욱 복잡한 행위를 구성한다.
좋아요!
그러나 더 좋은 것은 흐름과 파이프에 대해 우리가 필요로 하는 변화가 심지어 더 적다는 것이다.

contacts.stream()
 .sorted(compareByNameLength)
 .forEach(c -> System.out.println(c.getFirstName() + " " + c.getLastName()));
작은 매듭
이 장의 코드:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
public class Bar {
 public static void main(String[] args) {
//    long validContactCounter = contactList.parallelStream()
//    .map(s -> new Contact().setFirstName(s))
//    .filter(Contact::call)
//    .count();
  List<Contact> contacts = new ArrayList<Contact>() {{
   add(new Contact().setFirstName("Foo").setLastName("Jack"));
   add(new Contact().setFirstName("Bar").setLastName("Ma"));
   add(new Contact().setFirstName("Olala").setLastName("Awesome"));
  }};
  Comparator<Contact> byFirstName = new Comparator<Contact>() {
   @Override
   public int compare(Contact o1, Contact o2) {
    return Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));
   }
  };
  //--- Using Lambda form ---//
  Comparator<Contact> byFirstNameLambdaForm = (o1, o2) ->
    Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));
  Function<Contact, Character> keyExtractor = o -> o.getFirstName().charAt(0);
  Comparator<Character> keyComparator = (c1, c2) ->
    Character.compare(c1, c2);
  Comparator<Contact> byFirstNameAdvanced = (o1, o2) ->
    keyComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2));
  Comparator<Contact> compareByFirstName = Comparator.comparing(keyExtractor);
  Comparator<Contact> compareByNameLength = Comparator.comparing(p -> (p.getFirstName() + p.getLastName()).length());
  contacts.stream()
    .sorted(compareByNameLength)
    .forEach(c -> System.out.println(c.getFirstName() + " " + c.getLastName()));
 }
}
실행 결과:

Bar Ma
Foo Jack
Olala Awesome
위에서 말한 것은 편집자가 여러분께 소개한 자바에서 Lambda 표현식의 병행과 조합 행위입니다. 여러분께 도움이 되었으면 합니다. 만약에 궁금한 것이 있으면 저에게 메시지를 남겨 주십시오. 편집자는 제때에 여러분에게 회답할 것입니다.여기에서도 저희 사이트에 대한 지지에 감사드립니다!

좋은 웹페이지 즐겨찾기