안녕하세요? 개발자 "태민"입니다.
LIstView 속도개선을 위해서 많은 시도를 해봤습니다. 다만 밑의 링크에 굉장히 잘 정리되어 있으나, 언어장벽 또는 실제필요한 코드에 대한 설명이 부족한 것 같기에 제가 직접 실험하며, 실제 실험한 git주소를 올립니다.
(git주소는 밑에 기재하겠습니다.)
https://stackoverflow.com/questions/9008310/how-to-speed-adding-items-to-a-listview
조건, 실험방법
- 데이터 10000row listview에 add하기
- https://support.spatialkey.com/spatialkey-sample-csv-data/ 사이트의 데이터를 활용했습니다.
개선되기 전 코드
while (!reader.EndOfStream)
{
String line = reader.ReadLine();
String[] values = line.Split(',');
var item = new ListViewItem(values[0]);
foreach (String val in values)
{
item.SubItems.Add(val);
}
listView.Items.Add(item);
count++;
if (count > dataN)
break;
}
약 9.8초
method1_listView에 삽입 없이 돌리기
- add하는 부분을 빼고, 순수하게 csv파일에서 데이터를 꺼내는 속도만 계산한다.
while (!reader.EndOfStream)
{
String line = reader.ReadLine();
String[] values = line.Split(',');
var item = new ListViewItem(values[0]);
foreach (String val in values)
{
item.SubItems.Add(val);
}
// 순수하게 while문이 어느정도 걸리는지 계산한다.
// listView.Items.Add(item);
count++;
if (count > dataN)
break;
}
약 0초
(거의 모든 시간이 listView.add에 쓰이는 것을 알 수 있다.)
method2_listView에 Add하기전에 해당 listView update상태를 미리 선언
- while문(listView Add가 포함된 부분) 앞에 listview.BeginUpdate() 삽입
- while문뒤에 listview.EndUpdate() 삽입
//삽입부분
listView.BeginUpdate();
//삽입부분
while (!reader.EndOfStream)
{
String line = reader.ReadLine();
String[] values = line.Split(',');
var item = new ListViewItem(values[0]);
foreach (String val in values)
{
item.SubItems.Add(val);
}
listView.Items.Add(item);
count++;
if (count > dataN)
break;
}
//삽입부분
listView.EndUpdate();
//삽입부분
약 2.9초
(시간이 많이 줄은 것을 알 수 있다.)
Method3_ListViewItems를 우선 만들고, 나중에 add하기
- ListViewItem와 listview.add를 분리.
- 그렇기 때문에 가변Array인 List를 활용한다.
- 속도를 효과적으로 줄이기 위해 Method2를 같이 사용한다.
List<ListViewItem> items = new List<ListViewItem>();
//items 채우기
while (!reader.EndOfStream)
{
String line = reader.ReadLine();
String[] values = line.Split(',');
var item = new ListViewItem(values[0]);
foreach (String val in values)
{
item.SubItems.Add(val);
}
items.Add(item);
}
myLog("dataLoad.End");
myLog("listView.Items.Add(item).Start");
//items하나씩 listView 넣기
listView.BeginUpdate();
for (int i = 0; i < items.Count; i++)
listView.Items.Add(items[i]);
listView.EndUpdate();
약 13초
(시간이 더 늘어났다...)
시간을 줄이기 위한 추론
- 추론1. foreach(ListViewItem item in items) 자체가 시간이 많이 걸리는가?
실험. listView.Items.Add(items[i]);를 빼고 실행한다. -> 약 0초
결과. foreach(ListViewItem item in items) 자체의 시간은 많이 걸리지 않는다.
- 추론2.. listView.BeginUpdate()가 제대로 작동하지 않는가?
실험. listView.BeginUpdate()와 listView.EndUpdate()를 빼고 실행한다. -> 약 32초
결과. 시간이 더 늘어남에 따라 listView를 Update상태에 잘 진입하여 오히려 시간을 줄이고 있으나, 단톡으로 사용할 때마다 시간이 더 늘어났으므로 listView.BeginUpdate()은 method3과는 관련없다.
-추론3. foreach를 for문으로 바꾸면 더 빨라진다고 들어 이를 실험함.
실험. for (int i = 0; i < items.Count; i++) listView.Items.Add(items[i]); listView.EndUpdate(); 으로 코드를 수정. -> 약 12.5초
결과. 효과없음.
method4_Virtual Mode
- 실제 제공할 데이터를 필요할때 마다 RetrieveVirtualItem 이벤트 hook이 실행됨.
- 즉, listView에 어떤 변화가 생길 때마다 실행됨.
- 전체 항목에 대한 정렬불가
- Virtual Mode는 제약 조건이 많기 때문에 실제 프로젝트에 적용할 때 모든 기능이 작동 잘 되는지 확인해야 함.
- https://docs.microsoft.com/ko-kr/dotnet/api/system.windows.forms.listview.virtualmode?view=netcore-3.1 참고
// 소스코드는 밑 git주소를 확인해주세요.
즉시
ListView 개선을 위해서 많은 시도를 해보았는데 크게 개선된 것을 느끼긴 어려웠습니다. 하지만, method4인 virtual mode에 대한 설명이 많이 부족한 것을 알고 직접 코드로 구현했습니다. 많은 도움이 되길 바라며 제 git 주소를 올려놓겠습니다. 부족한 부분이나 틀린 부분이 있으면 지적해주시길 바랍니다.
https://github.com/taemtaemKim/listView_performanceImprovement
taemtaemKim/listView_performanceImprovement
listView_performanceImprovement. Contribute to taemtaemKim/listView_performanceImprovement development by creating an account on GitHub.
github.com
감사합니다.