스칼라를 살펴보고 싶어하며 답을 찾을 수없는 기본적인 질문이 하나 있습니다. 일반적으로 스칼라와 Java의 메모리 성능 및 사용에 차이가 있습니까?
스칼라를 살펴보고 싶어하며 답을 찾을 수없는 기본적인 질문이 하나 있습니다. 일반적으로 스칼라와 Java의 메모리 성능 및 사용에 차이가 있습니까?
답변:
스칼라는 엄청난 양의 메모리를 사용하지 않고도 사용하기가 매우 쉽습니다. 이것은 일반적으로 매우 강력하지만 때로는 성 가실 수 있습니다. 예를 들어, 문자열 배열 ( array
)과 해당 문자열을 파일 ( mapping
) 로 매핑 한다고 가정합니다 . 맵에 있고 길이가 2보다 큰 문자열에서 온 모든 파일을 가져오고 싶다고 가정하십시오. 자바에서는
int n = 0;
for (String s: array) {
if (s.length > 2 && mapping.containsKey(s)) n++;
}
String[] bigEnough = new String[n];
n = 0;
for (String s: array) {
if (s.length <= 2) continue;
bigEnough[n++] = map.get(s);
}
아휴! 힘든 일. 스칼라에서 동일한 작업을 수행하는 가장 간단한 방법은 다음과 같습니다.
val bigEnough = array.filter(_.length > 2).flatMap(mapping.get)
쉬운! 그러나 컬렉션이 작동하는 방식에 대해 잘 알고 있지 않는 한이 방법을 사용하면 추가 중간 배열 (with filter
)과 배열의 모든 요소 (with mapping.get
, 옵션). 또한 함수 객체가 작기 때문에 두 가지 함수 객체 (필터 용 필터와 flatMap 용 필터)를 만듭니다.
따라서 기본적으로 메모리 사용량은 기본 수준에서 동일합니다. 그러나 Scala의 라이브러리에는 많은 수의 (보통 수명이 짧은) 객체를 매우 쉽게 만들 수있는 많은 강력한 방법이 있습니다. 가비지 수집기는 일반적으로 이러한 종류의 가비지에 매우 적합하지만 사용중인 메모리에 대해 완전히 알지 못하는 경우 Java보다 Scala에서 더 빨리 문제가 발생할 수 있습니다.
Computer Languages Benchmark Game Scala 코드는 Java와 유사한 성능을 얻기 위해 다소 Java와 유사한 스타일로 작성되므로 Java와 같은 메모리 사용이 있습니다. Scala에서이를 수행 할 수 있습니다. 고성능 Java 코드처럼 보이도록 코드를 작성하면 고성능 Scala 코드가됩니다. (당신은 할 수 있습니다 더 관용적 스칼라 스타일을 작성하고 여전히 좋은 성능을 얻을 수 있지만, 세부 사항에 따라 달라집니다.)
프로그래밍 시간에 따라 스칼라 코드는 일반적으로 Java 코드보다 빠릅니다 . 스칼라에서는 번거롭지 않은 성능 비판적 부분을 적은 노력으로 수행 할 수 있으며 알고리즘 최적화 및 집중에 많은 관심을 기울일 수 있기 때문에 성능에 중요한 부분을위한 코드.
저는 새로운 사용자이므로 위의 Rex Kerr의 답변에 의견을 추가 할 수 없습니다 (새로운 사용자는 "응답"하지만 "댓글"은 허용하지 않는 것이 매우 이상한 규칙입니다).
나는 위의 Rex의 대중적인 대답에 대한 "조류, 자바는 너무 장황하고 열심히 일한다"라는 응답에 간단히 서명했다. 물론 더 간결한 스칼라 코드를 작성할 수는 있지만 주어진 Java 예제는 분명히 부풀어 오른다. 대부분의 Java 개발자는 다음과 같은 코드를 작성합니다.
List<String> bigEnough = new ArrayList<String>();
for(String s : array) {
if(s.length() > 2 && mapping.get(s) != null) {
bigEnough.add(mapping.get(s));
}
}
물론 Eclipse가 실제 입력을 대부분 수행하지 않고 저장된 모든 문자가 실제로 더 나은 프로그래머가되는 것처럼 가장한다면 다음과 같이 코딩 할 수 있습니다.
List b=new ArrayList();
for(String s:array)
if(s.length()>2 && mapping.get(s) != null) b.add(mapping.get(s));
이제는 전체 변수 이름과 중괄호를 입력하는 데 걸리는 시간을 절약 할뿐만 아니라 (깊숙한 알고리즘 적 사고를 생각하는 데 5 초 더 걸릴 수 있음) 난독 화 대회에 코드를 입력하고 잠재적으로 추가 현금을 얻을 수 있습니다 공휴일.
Arrays.stream(array).map(mapping::get).filter(x->x!=null).toArray(File[]::new);
스칼라를 Java와 같이 작성하면 거의 동일한 메트릭으로 거의 동일한 바이트 코드가 생성 될 것으로 예상 할 수 있습니다.
불변 개체와 고차 함수를 사용하여 더 "관용적으로"작성하면 조금 느리고 커집니다. 이 규칙에 대한 한 가지 예외는 type params가 사용하는 일반 객체를 사용할 때입니다.@specialised
주석을 권투 / 언 박싱을 피함으로써 Java 성능을 능가하는 더 큰 바이트 코드를 생성한다는 것입니다.
또한 병렬로 실행할 수있는 코드를 작성할 때 더 많은 메모리와 더 적은 속도가 불가피한 트레이드 오프라는 사실도 언급 할 가치가 있습니다. 관용 스칼라 코드는 일반적인 Java 코드보다 본질적으로 훨씬 선언적이며 종종 4 자 (.par
완전히 평행을 이루는 데 ) 정도 떨어져 있습니다.
그래서 만약
스칼라 코드가 25 % 느리거나 3 배 빠르다고 말할 수 있습니까?
정답은 "성능"을 정의하는 방법에 따라 다릅니다.
.par
2.9 에 언급하고 싶을 것 입니다.
.par
.
map
하며이 방법을 사용하지 않는 Scala 프로그램의 수는 거의 줄어 듭니다.
컴퓨터 언어 벤치 마크 게임 :
속도 테스트 java / scala 1.71 / 2.25
메모리 테스트 java / scala 66.55 / 80.81
따라서이 벤치 마크에서는 Java가 24 % 더 빠르며 스칼라는 21 % 더 많은 메모리를 사용한다고 말합니다.
전체적으로 큰 문제는 아니며 대부분의 시간이 데이터베이스와 네트워크에 의해 소비되는 실제 앱에서는 중요하지 않습니다.
결론 : 스칼라가 당신과 당신의 팀 (그리고 당신이 떠날 때 프로젝트를 인수하는 사람들)을 더 생산적으로 만들면, 그것을 사용해야합니다.
내가 언급 한 Rex Kerr의 예제간에 명백한 성능 차이가있는 것처럼 보이지만 다른 사람들은 타이트 루프와 관련 하여이 질문에 대답했습니다.
이 답변은 실제로 설계 결함으로 타이트한 루프 최적화의 필요성을 조사 할 수있는 사람들을 대상으로합니다.
나는 스칼라를 처음 접했지만 (약 1 년 정도), 지금까지 느낌은 당신이 연기 할 수 있다는 것입니다 은 디자인, 구현 및 실행의 여러 측면을 비교적 쉽게 (충분한 배경 읽기 및 실험
지연된 디자인 기능 :
지연된 구현 기능 :
지연된 실행 기능 : (죄송합니다, 링크가 없습니다)
이 기능은 빠르고 엄격한 응용 프로그램으로가는 길을 걷는 데 도움이되는 기능입니다.
Rex Kerr의 예제는 실행 측면이 지연되는 점이 다릅니다. Java 예제에서 메모리 할당은 스칼라 예제가 맵핑 조회를 지연시키는 크기가 계산 될 때까지 지연됩니다. 나에게는 완전히 다른 알고리즘처럼 보입니다.
다음은 Java 예제에 해당하는 사과 대 사과에 가깝습니다.
val bigEnough = array.collect({
case k: String if k.length > 2 && mapping.contains(k) => mapping(k)
})
어떤 중간 컬렉션도없고, Option
인스턴스 등이 또한 이렇게 수집 유형 보존 bigEnough
의 유형이다 Array[File]
- Array
의collect
구현 아마 씨 커의 자바 코드가 수행하는 작업의 라인을 따라 뭔가를하고있는 것입니다.
위에 나열된 지연된 디자인 기능을 통해 Scala의 수집 API 개발자는 API를 중단하지 않고 향후 릴리스에서 빠른 어레이 별 수집 구현을 구현할 수 있습니다. 이것이 속도로가는 길을 언급하는 것입니다.
또한:
val bigEnough = array.withFilter(_.length > 2).flatMap(mapping.get)
withFilter
내가 대신 여기에 사용했다고 방법을 filter
수정 중간 수집 문제를하지만 옵션 인스턴스 문제가 여전히 존재한다.
스칼라에서 간단한 실행 속도의 한 예는 로깅입니다.
Java에서는 다음과 같이 작성할 수 있습니다.
if (logger.isDebugEnabled())
logger.debug("trace");
스칼라에서 이것은 다음과 같습니다.
logger.debug("trace")
스칼라에서 디버깅 할 메시지 매개 변수는 " => String
" 타입을 가지고 있기 때문에 평가할 때 실행되는 매개 변수가없는 함수로 생각되지만 문서는 이름으로 전달합니다.
편집 {스칼라의 함수는 객체이므로 여기에 추가 객체가 있습니다. 내 작품에서 사소한 객체의 무게는 로그 메시지가 불필요하게 평가 될 가능성을 제거 할 가치가 있습니다. }
이렇게하면 코드가 더 빨라지지는 않지만 더 빨라질 수 있으며 다른 사람의 코드를 대량으로 정리하고 정리하는 경험이 줄어 듭니다.
나에게 이것은 스칼라에서 일관된 테마입니다.
하드 코드는 Scala가 조금 더 힌트가 있지만 왜 더 빠른지 캡처하지 못합니다.
스칼라에서는 코드 재사용과 코드 품질 한도의 조합이라고 생각합니다.
Java에서 멋진 코드는 종종 이해할 수없는 혼란이되므로 대부분의 프로그래머가 사용할 수 없으므로 프로덕션 품질 API 내에서 실제로 실행되지 않습니다.
스칼라가 아인슈타인이 DSL을 통해 표현 될 수있는 훨씬 더 유능한 API를 구현할 수 있기를 희망합니다. 스칼라의 핵심 API는 이미이 경로를 따르고 있습니다.
Java와 Scala는 모두 JVM 바이트 코드로 컴파일되므로 차이점은 그다지 크지 않습니다. 가장 좋은 비교는 아마도 컴퓨터 언어 벤치 마크 게임 일 것입니다. 기본적으로 Java와 Scala는 모두 동일한 메모리 사용량을 가지고 있습니다. 스칼라는 열거 된 일부 벤치 마크에서 Java보다 약간 느리지 만 프로그램의 구현이 다르기 때문일 수 있습니다.
하지만 둘 다 너무 가까워 걱정할 필요가 없습니다. 스칼라와 같이보다 표현력이 뛰어난 언어를 사용함으로써 얻을 수있는 생산성 향상은 최소한의 성능 저하보다 훨씬 가치가 있습니다.
Java and Scala both compile down to JVM bytecode,
과 결합 된 진정한 진술 은 논증적인 결론이 아니라 수사법 이라는 것을 보여줍니다 . so
diffence isn't that big.
so
Java 예제는 실제로 일반적인 응용 프로그램의 관용구가 아닙니다. 이러한 최적화 된 코드는 시스템 라이브러리 메소드에서 찾을 수 있습니다. 그러나 올바른 유형의 배열, 즉 File []을 사용하고 IndexOutOfBoundsException을 발생시키지 않습니다. (카운팅 및 추가를위한 다른 필터 조건). 내 버전은 (중괄호로 항상 (!)입니다. Eclipse에서 단일 키를 누르기 위해 2 초를 절약하여 소개 된 버그를 검색하는 데 시간을 소비하지 않기 때문에) :
List<File> bigEnough = new ArrayList<File>();
for(String s : array) {
if(s.length() > 2) {
File file = mapping.get(s);
if (file != null) {
bigEnough.add(file);
}
}
}
그러나 현재 프로젝트에서 다른 못생긴 Java 코드 예제를 많이 가져올 수 있습니다. 일반적인 구조와 동작을 고려하여 일반적인 복사 및 수정 스타일의 코딩을 피하려고했습니다.
내 추상 DAO 기본 클래스에는 공통 캐싱 메커니즘에 대한 추상 내부 클래스가 있습니다. 모든 구체적인 모델 오브젝트 유형에 대해 추상 DAO 기본 클래스의 서브 클래스가 있으며, 내부 클래스는 비즈니스 오브젝트가 데이터베이스에서로드 될 때 비즈니스 오브젝트를 작성하는 메소드에 대한 구현을 제공하기 위해 서브 클래 싱됩니다. 독점 API를 통해 다른 시스템에 액세스하므로 ORM 도구를 사용할 수 없습니다.
이 서브 클래 싱 및 인스턴스화 코드는 Java에서 전혀 명확하지 않으며 Scala에서 매우 읽기 쉽습니다.