(블로그 이사하면서 옮겨진 글입니다)
C#에는 멀티쓰레드 프로그래밍을 도와주는 ConcurrentQueue, ConcurrentDictionary같은 자료구조들이 있다. 그래서 기본적으로는 싱글쓰레드에서만 접근할 때는 Dictionary, 멀티쓰레드에서 접근할때는 ConcurrentDictionary를 쓰는데, 문득 'Dictionary를 안써도 되는게 아닐까?'라는 생각이 들었다. ConcurrentDictionary가 Dictionary보다 느린 건 당연하지만 느린 정도가 프로그램에 영향을 끼치지 않는 수준이라면 모든 Dictionary를 ConcurrentDictionary로 교체할 수 있을 것이다. 그래서 두개의 성능을 비교해보기로 했다.
ConcurrentDictionary | Dictionary | |
---|---|---|
Total | 334.3ms | 30.3ms |
Max | 124.7ms | 34.4ms |
ConcurrentDictionary | Dictionary | |
---|---|---|
Total | 34.6ms | 8.8ms |
ConcurrentDictionary | Dictionary | |
---|---|---|
Total | 4.6ms | 2.9ms |
구체적인 수치는 실험실환경이랑은 많이 동떨어진 개인용 윈도우 컴퓨터에서 측정되었기 때문에 많은 오차가 있을 수 있다. 하지만 ConcurrentDictionary에는 무시할 수 없을만큼의 성능차이가 존재한다는 사실은 확인할 수 있다.
또한 Add에서는 특별히 시간차이가 많이 난다. 그래서 capacity가 1이기 때문에 Resize에서 시간차이가 많이 나기 때문이라고 생각해서 Capacity를 1억으로 설정하고 비교해본 결과
ConcurrentDictionary | Dictionary | |
---|---|---|
Total | 129.9ms | 17.0ms |
Max | 13.5ms | 0.1ms |
여전히 많은 차이가 났다.
capacity를 늘려도 key 충돌에 의해 resize로직이 돌 수 있는게 문제인 듯 했다. 한 item을 add하는데 1ms이상 걸리는 경우가 concurrentDictionary에 한해서 몇번 발생하고 이게 키 충돌에의한 resize가 아닐까 추측된다. (comparer만들고 getHashCode 구현하면 이것도 없앨 수 있을 것 같지만 거기까지 하긴 귀찮았다) 왜 concurrentDictionary에서만 이런 resize과정이 일어나는지에 대한 자세한 내용은 ConcurrentDictionary 코드와 Dictionary 코드를 직접 확인해보자.
결론적으로, 성능차이가 많이나기 때문에 성능에 어느정도 민감한 프로그램에서는 Dictionary 대신 ConcurrentDictionary를 쓰진 못할 듯 하다. 하지만 Dictionary가 5배 이상 느려도 별 문제가 없어보인다면 추가 프로파일링 과정을 거친 후에 도입을 고민해볼 수는 있을 것 같다.