2011-12-22 6 views
2

ConcurrentHashMap을 캐시로 사용하는 주식 시장 시뮬레이터를 작성했습니다.고성능 캐시 작성

캐시에는 약 75 개의 요소가 있지만 매우 신속하게 업데이트되고 검색됩니다 (초당 500 회). 여기

내가 무슨 짓을 :

스레드 1 :

주어진 주식 기호에 대한 스트리밍 따옴표로 날을 제공하는 외부 시스템에 연결되었습니다.

2 스레드 (스레드 콜백)까지 데이터

대기는 외부 시스템에 의해 그것으로 전달된다. 데이터를 가져 오면 파싱하고, 불변의 DataEntry 객체를 생성하고, 캐시하고, thread3에 신호를 보냅니다.

스레드 3 (소비자 스레드) : 신호를 수신하면 캐시에서 DataEntry를 검색하여 사용합니다. (이것은 thread2가 thread3에 직접 데이터를 푸시하지 못하게하는 작업의 일부입니다).

public final class DataEntry{ 

     private final String field1; 
     private final String field2; 
     //... 
     private final String field25; 

     // Corresponding setters and getters 

} 

public final class Cache{ 

     private final Map<String, DataEntry> cache; 

     public Cache(){ 
      this.cache = new ConcurrentHashMap<String, DataEntry> (65, 0.75, 32); 
     } 

     // Methods to update and retrieve DataEntry from the cache. 
} 

프로파일 러를 통해 실행 한 후, 나는 내가 많은 DataEntry 개체의를 만드는 오전 것으로 나타났습니다. 그러므로 에덴은 매우 빨리 채워지고 있습니다.

그래서 나는하여 디자인을 약간 조정의 생각입니다 :

A)DataEntry 클래스를 변경할 만들기.

b) 캐시를 빈 DataEntry 개체로 미리 채 웁니다.

c) 업데이트가 도착하면 DataEntry 개체를지도에서 검색하고 채 웁니다.

이 방법으로, DataEntry 개체의 수는 일정하고 요소 수와 같습니다.

내 질문은 :이 디자인은 내가 DataEntry 가변함으로써 도입 수있는 동시성 문제가

A)는 않습니다.

b) 캐시를 최적화하기위한 다른 방법이 있습니까?

감사합니다.

+0

초당 백만 번 이상 ConcurrentHasMap에 액세스 할 수 있으며 액세스 할 수있는 경우에는 영향이 없습니다 초당 시간. –

+0

16 개 이상의 코어가 맵에 한 번에 액세스 할 것으로 예상되는 경우 파티션 크기를 늘립니다. 한 번에지도에 액세스하는 4 코어보다 적은 코어를 사용하는 경우 (다른 작업은하지 않음), 그다지 큰 차이는 없을 것입니다. –

+0

에덴이 빨리 채워지는 것이 왜 문제가됩니까? Eden GC로 인해 실제로 문제가 있습니까? – kdgregory

답변

1

나는 ConcurrentHashMap의

의 속도에 대해
Map<Integer, Integer> map = new ConcurrentHashMap<>(); 
long start = System.nanoTime(); 
int runs = 200*1000*1000; 
for (int r = 0; r < runs; r++) { 
    map.put(r & 127, r & 127); 
    map.get((~r) & 127); 
} 
long time = System.nanoTime() - start; 
System.out.printf("Throughput of %.1f million accesses per second%n", 
     2 * runs/1e6/(time/1e9)); 

인쇄

Throughput of 72.6 million accesses per second 

이 지금까지 사용을 한 것으로 나타났습니다 액세스 속도 넘어 걱정하지 않을 것입니다.

가비지를 줄이려면 변경 가능한 객체와 프리미티브를 사용할 수 있습니다. 이러한 이유 때문에 String을 사용하는 것을 피할 것입니다 (데이터 항목보다 훨씬 많은 문자열을 가지고있는 것처럼 보입니다)

+0

감사합니다. 한 번 더 질문을 드리면 DataEntry를 변경 가능하게 만들면지도에 추가하는 동안지도를 고정해야합니다. 그렇지 않습니다. 또는 AtomicReference를 사용하여 변경 가능한 DataEntry를 래핑 할 수 있습니까? 건배 (BTW, 당신의 블로그를 사랑해). – CaptainHastings

+1

동시성이 높은 시스템의 경우, 기본 동시 해시 맵은 좋은 생각이 아니지만, 설명에서 볼 수있는 것 같지 않습니다. (여기에서 YMMV와 매우 비슷한 수십 개의 스레드 이상을 고려해야합니다) . 설명에서 해시 맵은 이상한 선택입니다. – Voo

+0

변경 가능한 DataEntry를 사용하는 경우, 한 번만 추가 할 것입니다 (가급적이면 시작시에). 악기 당 둘 이상이 필요합니까? 블로그에 대한 환호성. ;) –

1

사용하는 것처럼 그것은 소리 ConcurrentHashMap 때 무엇을 정말 필요가 동시 큐 같은 것입니다 -하는 LinkedBlockingQueue라고?

+0

안녕하세요, 실제로 이해 관계자가 새 데이터를 폴링하지 않고 폴링하도록 맵을 만들어야합니다. – CaptainHastings

+1

흠 ...지도가 여전히 최상의 데이터 구조라는 것은 확실하지 않습니다. 각 "이해 관계자"에 대해 별도의 대기열을 사용하는 것에 대해 생각해 보셨습니까? –

1
  • a. 네, 그렇습니다.은 읽을 수없는 상태에서 객체를 업데이트 할 수있어 일관성없는 상태가 될 수 있습니다.
  • b. 가능합니다 : 요청시 변경할 수있는 DataEntry을 반환하는 변경 가능한 DataEntryCache을 만듭니다. 이렇게하면 새로운 DataEntry 개체를 쓰기 작업이 아닌 읽기 작업에 생성 할 수 있습니다. DataEntryCache은 내부적으로 구성하고 반환하는 변경 불가능한 DataEntry을 캐시 할 수 있으며 변경 호출시 해당 "캐시"를 무효화 할 수 있습니다.

편집 : 캐싱하는 이유는 (스레드 2와 3 사이의 대기열을 만드는 것과는 대조적으로) 소비자 스레드가 스레드 2가 다른 하나를 읽는 것 외에 다른 항목을 읽을 수 있다고 가정합니다. 공고. 이 가정이 맞지 않으면 캐시가 전혀 필요하지 않을 수 있습니다.

+0

+1, b에 대한 귀하의 답이 저에게 경쟁 조건처럼 보입니다. – kdgregory

+0

안녕하세요, 이해 관계자에게 새로운 데이터를 보내고 설문 조사를 요청할 수 있도록지도가 필요합니다. – CaptainHastings

+0

@kdgregory이 작업은'DataEntryCache' 내부에서 동기화되어야합니다. – dasblinkenlight

0

a) 내 코드 개체 생성시 자주 병목 현상이 발생하므로 DataEntry 개체를 재사용한다고 생각하는 것이 좋습니다. 그러나 kdgregory가 주석을 달았으므로 현재 요소를 덮어 쓰면 일관성없는 항목이 읽히게됩니다. 따라서 항목을 업데이트 할 때 새로운 항목 또는 사용 가능한 경우 재사용 대기 (몇 분 동안 유휴라고 표시) 항목에 쓰고지도에 넣으십시오. 새 항목을 맵에 넣은 후 이전 항목을 일종의 유휴 목록에 넣습니다. 완전히 안전하려면 읽기 스레드가 캐시에 의해 전달 된 DataEntry에 액세스 할 수 없어야합니다. 1 분. 스레드가 차단 될 수 있으면 DataEntry 객체를 복사해야합니다.이 경우 자체 객체를 재사용해야합니다.

b) 현재 디자인은 모듈 식이지만 스레드가 모듈을 반영하기 때문에 많은 컨텍스트 전환이 필요합니다. 나는 하나의 요청이 단일 스레드에 의해 처음부터 끝까지 제공되는 디자인을 시도 할 것이다. 요청은 새 DataEntry 개체의 전체 처리 일 수 있습니다. 이를 달성하는 동시성 디자인 패턴은 Leader/FollowerHalf-Sync/Half-Asynch입니다.

+0

"명백한 동시성 문제가 보이지 않습니다"- 다른 스레드가 값을 쓰는 동안 한 스레드가 객체에서 값을 읽는 경우 어떻게됩니까? – kdgregory

+0

링크를 이용해 주셔서 감사합니다. – CaptainHastings

+0

@kdgegory, 감사합니다. 그 * 분명했다;). 나는 나의 대답을 업데이트했다. –