• 検索結果がありません。

5-D オラクルコンサルが語るJava SE 8の勘所

N/A
N/A
Protected

Academic year: 2021

シェア "5-D オラクルコンサルが語るJava SE 8の勘所"

Copied!
85
0
0

読み込み中.... (全文を見る)

全文

(1)

オラクルコンサルが語る

Java SE 8 の勘所

日本オラクル株式会社

コンサルティング統括本部

プリンシパルコンサルタント

伊藤 智博

Java Day Tokyo 2016

(2)

Safe Harbor Statement

The following is intended to outline our general product direction. It is intended for

information purposes only, and may not be incorporated into any contract. It is not a

commitment to deliver any material, code, or functionality, and should not be relied upon

in making purchasing decisions. The development, release, and timing of any features or

functionality described for Oracle’s products remains at the sole discretion of Oracle.

(3)

自己紹介

伊藤 智博(いとうちひろ)

コンサルティングサービス統括所属

インメモリ高速処理基盤の構築を支援

Javaに関わるトラブルシューティング

国内外問わずJavaのイベントで講演

(4)
(5)

Java SE 8

について

(6)

"旧来の日付APIで十分だし、

(7)

"Lambda式?

複雑そうだし、処理に

(8)

"Stream API?

(9)

こんな疑問を

パフォーマンス分析

の観点で

(10)

アジェンダ

1.

Date and Time API

2.

Lambda式

3.

Stream API

Java Flight Recorder

(11)

Java Flight Recorderとは

アプリケーションとJVMの情報を記録

(12)

主な分析観点

CPUリソースの割り当て

JVMに中断された時間

(13)
(14)

よく行われる日付の処理

"2016/05/24"

2016/05/24

変換

文字列

日付オブジェクト

2016/05/31

計算

(15)

これまでの実装方法

SimpleDateFormat formater =

new

SimpleDateFormat

(

"yyyy/MM/dd"

);

Date date = formater.

parse

(

"2016/05/24"

);

Calendar

cal

= Calendar.getInstance();

cal

.setTime(date);

cal

.set(

DATE

,cal.getActualMaximum(

DATE

));

Date end = cal.getTime();

イミュータブルではない

スレッドセーフではない

重い

(16)

Date and Time API とは

JSR 310 として標準化された日時API

これまでのAPIと互換性は無い

スレッドセーフ

データ形式ごとにクラスを定義

イミュータブル

(17)

文字列からオブジェクトへ変換手順

1.

形式を指定してフォーマッタを作成

形式の例:yyyy/MM/dd

2.

フォーマッタと文字列からオブジェクトを作成

文字列の例:2016/05/24

1

2

"2016/05/24"

変換

2016/05/24

文字列

日付オブジェクト

(18)

変換コードの比較

SimpleDateFormat formater =

new

SimpleDateFormat(

"yyyy/MM/dd"

);

Date date = formater.parse(

"2016/05/24"

);

DateTimeFormatter

formater =

DateTimeFormatter.ofPattern

(

"yyyy/MM/dd"

);

LocalDate

date =

LocalDate.parse

(

"2016/05/24"

, formater);

1

2

2

1

(19)

月末日の取得手順

1.

計算をするための日付オブジェクトの取得

2.

日付オブジェクトに末日を設定

3.

欲しいクラスの日付オブジェクトへ変換

1

2

3

2016/05/24

日付オブジェクト

2016/05/31

計算

(20)

月末日の取得コードの比較

Calendar cal = Calendar.getInstance();

cal.set(DATE

,cal.getActualMaximum(

DATE

));

Date end = cal.getTime();

LocalDate

end = YearMonth.now().

atEndOfMonth

();

1

2

3

(21)
(22)

パフォーマンス分析するケース

"2016/05/24"

2016/05/24

変換

文字列

日付オブジェクト

2016/05/31

計算

(23)

ケース1:変換処理

処理

日付文字列から日付オブジェクトを変換

分析観点

CPUリソースの割り当て

GCの実行時間

変換にかかった処理時間

(24)

リソースと中断時間を確認

CPUが使えたか

を確認

GCの実行時間を

確認

(25)

検証環境

ハードウェア

CPU 4コア

メモリ 16GB

Java VM

ヒープ 4GB (New 3GB, Eden 2.88GB)

(26)

ケース1:変換処理のコード比較(再掲

SimpleDateFormat formater =

new

SimpleDateFormat(

"yyyy/MM/dd"

);

Date date = formater.parse(

"2016/05/24"

);

DateTimeFormatter formater =

DateTimeFormatter.ofPattern(

"yyyy/MM/dd"

);

LocalDate date =

(27)

リソース使用量

これまでの方法

Date and Time API

1つのコアを使用できている

(28)

ケース1:GC停止時間

68.3

71.5

0

20

40

60

80

これまでの方法

Date and Time API

ms

ms

ms

(29)

ケース1:処理時間

180

106

0

60

120

180

240

これまでの方法

Date and Time API

(30)

ケース2:オブジェクトのサイズ

処理

1.

日付オブジェクトを生成・保持

1000万オブジェクト

2.

Full GC

分析観点

FullGCをした後のヒープ使用量

(31)

FullGC後のヒープ使用量の確認

GCを選択

(32)

FullGC後のヒープ使用量の確認

(33)

ケース2: ヒープ使用量

284

284

0

100

200

300

400

java.util.Date

java.time.LocalDate

MB

MB

MB

±

0

%

(34)

まとめ

処理の流れはほぼ同一に実装可能

処理時間は40%以上

短縮

日付オブジェクトの

ヒープ使用量は同等

(35)
(36)

インターフェースについて

インターフェース

本番実装

モック実装

インターフェース

関数型インターフェース

1つのメソッドのみ定義

(37)

名前付きのクラスによる実装

匿名クラスによる実装

インターフェースの実装方法

class

Impl

implements

Iface {

@Override

public void

method1(){

// 処理

}

}

Iface o =

new

Iface() {

@Override

public void

method1(){

// 処理

}

};

(38)

これまでの実装方法とその嫌な点

IntPredicate func =

new

Intpredicate(){

public boolean

test(

int

param){

return

param %

2

==

0

;

}

};

開発者は

関心事だけに集中

したい

(39)

Lambda式 とは

関数型インターフェースを簡単に実装する記法

( 引数 )-> { 本体 }

Stream APIとの親和性が高い

Java SE 7 以前のインターフェースにも使える

実行時に多くのクラスをロード

(40)

Lambda式への変換方法

IntPredicate func =

new

Intpredicate(){

public boolean

test(

int

param){

return

param %

2

==

0

;

}

};

IntPredicate func = param

->

param %

2

==

0

;

(41)
(42)

ケース:実装方法による処理時間

処理

指定した数が素数かどうかを確認する

あえて条件式をLambda式で書いた方法を比較

分析観点

コンパイル数およびコンパイル時間

処理時間

(43)

素数とは

1とその数自身のみで割りきれる数(2,3,5,7,11,…)

素数の候補となる数 n を 2 から n-1 までの数で

割り切れなければ(余り≠0)素数である

(44)

コンパイル数の確認方法

コンパイル

された

メソッド数

(45)

コンパイル時間の確認方法

コンパイルの

情報から時間を

算出

(46)

Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |

ケース:テストコード

boolean

isPrime =

true

;

for

(

int

div =

2

; div < candidate; div

++

)

if

(

candidate % div == 0

) isPrime =

false

;

IntPredicate func = div -> (candidate % div == 0);

for

(

int

div =

2

; div < candidate; div

++

)

if

(

func.test(div)

) isPrime =

false

;

(47)

リソース使用量

for文

lambda式

ヒープ使用量

9.4

MB

ヒープ使用量

10.7

MB

(48)

コンパイル数の確認

66

メソッド

312

メソッド

(49)

コンパイル時間の比較

154

371

0

100

200

300

400

for文

Labmda式

ms

ms

ms

+140

%

(50)

処理時間の比較

55.0

53.3

0

15

30

45

60

for文

Labmda式

-3.1

%

(51)

まとめ

コンパイルされるメソッド数が増加

コンパイル時間が増加

実行時間に比べると

微増

(52)
(53)

繰り返し内で行われる処理

中間操作(途中で行う処理)

情報のフィルタ、情報の変換

終端操作(最終的に行う処理)

(54)

繰返し処理の種類

for

(

要素

e : 集合)

処理

集合.終端操作用メソッド(

処理

);

外部イテレータ:(繰返しを外に書く)

内部イテレータ:(繰返しを内部で隠蔽する)

(55)

30歳以上の社員名を集める実装例

Collection<Employee> empCol = ...;

List<String> list =

new

ArrayList<>();

for

(Employee e : empCol)

if

( e.getAge() >=

30

)

list.add( e.getName() );

中間操作

終端操作

終端操作

外部イテレータ

(56)

これまでの実装方法の嫌な点

同じようなコードが多くメンテナンス性に欠ける

for文の前でコレクションを作って、中でaddして…

スループットの向上が困難

1回あたりの処理の粒度が小さいために速度向上が困難

マルチスレッドに分割する開発コストが高い

(57)

Stream API とは

内部イテレータによる繰返し処理

主にCollectionインターフェースに定義

中間操作と終端操作を組み合わせて処理を実行

Fork Join Frameworkでパラレル化を実現

(58)

Stream APIのメソッド例

中間操作

情報のフィルタ(

filter

)、情報の変換(

map

)

終端操作

戻り値無し(

foreach

)、戻り値あり(

collect

など)

内部イテレータ

empCol.stream().collect(処理);

(59)

Parallel Stream

システムプロパティで多重度を設定可能

java.util.concurrent.ForkJoinPool.common.parallelism

デフォルト値はコア数

empCol.stream().parallel().collect(処理);

empCol.parallelStream().collect(処理);

(60)

繰返し処理のコード比較

List<String> list =

new

ArrayList<>();

for

(Employee e : empCol)

if

( e.getAge() >=

30

) list.add( e.getName() );

List<String> list =

empCol.

stream()

.

filter

(e->e.getAge() >=

30

)

(61)
(62)

分析するケース

実装方法

スレッド数

for文

1

Stream

1

Parallel Stream

1

2

3

(63)

検証環境

Oracle Exalogic X5-2

Intel Xeon CPU E5-2699 v3

2.3GHz

18コア

HT

あり

2 プロセッサ

(64)

ケース1:実装方法ごとの処理時間

処理

from から to までにある素数を数える

for文、Stream、Parallel Stream(1スレッド)

分析観点

CPU使用率

スレッドの処理割合

オーバーヘッドの確認

(65)

リソース使用量の確認

CPUが使えたかを

確認

処理をしている

スレッド数を確認

(66)

オーバーヘッドを確認

素数を判断する

メソッドまでの

処理階層を確認

(67)

for文のコード

int

primeNum =

0

;

for

(

int

candidate=

from

; candidate<=

to

; candidate

++

)

{

if

(

PrimeUtil.isPrimeFunc

(candidate) ){

primeNum

++

;

}

}

(68)

Stream APIのコード

long

num =IntStream.rangeClosed(

from

,

to

)

.filter(PrimeUtil::isPrimeFunc).count();

long

num =IntStream.rangeClosed(

from

,

to

).

parallel()

.filter(PrimeUtil::isPrimeFunc).count();

Stream

(69)

リソース使用量

for文

Stream

Parallel Stream

1コアを使用できている

(70)

実装方法による処理階層の深さ

3

13

22

0

10

20

30

for文

Stream

Parallel Stream

(71)

実装方法による処理時間の比較

201

208

212

0

50

100

150

200

250

for文

Stream

Parallel Stream

(72)

ケース2:パラレル化

処理

from から to までにある素数を数える

1~72スレッドまでスレッド数を増加

分析観点

CPU使用率

スレッドの処理割合

処理時間

(73)

リソース使用量(1と3スレッド)

1

スレッドを設定

スレッドを設定

CPU使用率が3倍に増加

(74)

1~18スレッドの処理時間推移

51.3%

33.6%

18.2% 12.8%

7.0%

0%

25%

50%

75%

100%

1

2

3

6

9

18

スレッド数

処理時間

CPU使用率

スレッド数増加に伴い

処理時間は短縮

(75)

リソース使用量(18と36スレッド)

18

スレッドを設定

36

スレッドを設定

(76)

18と36スレッドの処理時間推移

56.8%

0%

25%

50%

75%

100%

18

スレッド数

36

処理時間

CPU使用率

処理時間は約半減

(77)

リソース使用量(36と72スレッド)

36

スレッドを設定

72

スレッドを設定

(78)

36と72スレッドの処理時間推移

90.5%

0%

25%

50%

75%

100%

36

スレッド数

72

処理時間

CPU使用率

処理時間は微減

→HTとCPU使用率に注意

(79)

スレッド数毎の処理時間推移まとめ

7.0% 4.0%

3.6%

0%

25%

50%

75%

100%

1

18

36

72

スレッド数

処理時間

CPU使用率

(80)

まとめ

Stream APIの

オーバーヘッドは微少

処理を

簡単にパラレル化

できる

マルチコア・マルチプロセッサの効果大

(81)

全体のまとめ

処理時間は短縮

リソース使用量は微増

パフォーマンス以外にもメリット

(82)

Safe Harbor Statement

The preceding is intended to outline our general product direction. It is intended for

information purposes only, and may not be incorporated into any contract. It is not a

commitment to deliver any material, code, or functionality, and should not be relied upon

in making purchasing decisions. The development, release, and timing of any features or

functionality described for Oracle’s products remains at the sole discretion of Oracle.

(83)
(84)
(85)

参照

関連したドキュメント

Since the boundary integral equation is Fredholm, the solvability theorem follows from the uniqueness theorem, which is ensured for the Neumann problem in the case of the

Next, we prove bounds for the dimensions of p-adic MLV-spaces in Section 3, assuming results in Section 4, and make a conjecture about a special element in the motivic Galois group

Transirico, “Second order elliptic equations in weighted Sobolev spaces on unbounded domains,” Rendiconti della Accademia Nazionale delle Scienze detta dei XL.. Memorie di

In this diagram, there are the following objects: myFrame of the Frame class, myVal of the Validator class, factory of the VerifierFactory class, out of the PrintStream class,

For X-valued vector functions the Dinculeanu integral with respect to a σ-additive scalar measure on P (see Note 1) is the same as the Bochner integral and hence the Dinculeanu

Giuseppe Rosolini, Universit` a di Genova: [email protected] Alex Simpson, University of Edinburgh: [email protected] James Stasheff, University of North

p≤x a 2 p log p/p k−1 which is proved in Section 4 using Shimura’s split of the Rankin–Selberg L -function into the ordinary Riemann zeta-function and the sym- metric square

information, product features, availability, functionality, or suitability of its products for any particular purpose, nor does onsemi assume any liability arising out of