C# 초보 질문 있습니다.

C# 닷넷7 으로 프로그램을 만들었습니다.
opencvsharp 사용하여 이미지 구별하는 프로그램입니다.
잘 작동되는 프로그램이었습니다. 근대 새로운 기능을 넣기 위해서 특정함수를
넣었는데 랙이 발생하네요. 물론 하드웨어 용량은 충분합니다. CPU 사용률 30%, 메모리 사용률 30% 정도입니다. 아무리 생각해봐도 병목현상 원인을 모르겠습니다.
그래서 새로운 기능을 위한 특정함수 코드를 적어보겠습니다.
꼭 알려주세요.

public static async Task ExecuteCMDAsync(string text1, string text2, string text3, string text4)
{
ProcessStartInfo pri = new ProcessStartInfo();
Process pro = new Process();

 pri.FileName = @"cmd.exe";
 pri.CreateNoWindow = true;
 pri.UseShellExecute = false;

 pri.RedirectStandardInput = true;
 pri.RedirectStandardOutput = true;
 pri.RedirectStandardError = true;

 pro.StartInfo = pri;
 pro.Start();

 await Task.Delay(9000);
 await pro.StandardInput.WriteLineAsync(text1 + Environment.NewLine);
 await Task.Delay(9000);
 await pro.StandardInput.WriteLineAsync(text2 + Environment.NewLine);
 await Task.Delay(9000);
 await pro.StandardInput.WriteLineAsync(text3 + Environment.NewLine);
 await Task.Delay(9000);
 await pro.StandardInput.WriteLineAsync(text4 + Environment.NewLine);
 await Task.Delay(9000);

 pro.StandardInput.Close();

 string resultValue = await pro.StandardOutput.ReadToEndAsync();
 await pro.WaitForExitAsync();
 pro.Close();

}

public static async Task ExecuteADBAsync(int num)
{
int nnum = 5555 + 10 * num;
string portnum = nnum.ToString();

 await ExecuteCMDAsync("adb connect 127.0.0.1:" + portnum,
                       "adb -s 127.0.0.1:" + portnum + " shell am force-stop com.xxx.xxxx.xxx",
                       "adb -s 127.0.0.1:" + portnum + " shell am start -n com.xxx.xxxx.xxx/com.toast.android.gamebase.activity.MainActivity",
                       "adb disconnect 127.0.0.1:" + portnum);
 await Task.Delay(5000); 

}

public static async Task IsStoppedAsync(int num)
{
OpenCvSharp.Rect rect = new OpenCvSharp.Rect(390, 322, 8, 5);

 if (stoppedMat[num] == null)
 {
     Mat sscreenMat = new Mat();
     gameCapture[num].CopyTo(sscreenMat);

     Cv2.CvtColor(sscreenMat, sscreenMat, ColorConversionCodes.BGR2GRAY);
     Mat roiMat = sscreenMat.SubMat(rect);

     if (stoppedMat[num] == null)
     {
         stoppedMat[num] = new Mat();
     }

     roiMat.CopyTo(stoppedMat[num]);

     sscreenMat.Dispose();
     roiMat.Dispose();
 }
 else if (스톱반복횟수[num] >= 50)
 {
     Mat findimg = new Mat();
     stoppedMat[num].CopyTo(findimg);

     Mat ScreenMat = new Mat();
     gameCapture[num].CopyTo(ScreenMat);

     Mat grayImage = new Mat();
     Cv2.CvtColor(ScreenMat, grayImage, ColorConversionCodes.BGR2GRAY);

     Mat roiImage = grayImage.SubMat(rect);
     double acc = 0;

     using (var res = roiImage.MatchTemplate(findimg, TemplateMatchModes.CCoeffNormed))
     {
         double minval, maxval;
         OpenCvSharp.Point minloc, maxloc;

         Cv2.MinMaxLoc(res, out minval, out maxval, out minloc, out maxloc);
         acc = maxval;
     }

     if (acc >= 0.97)
     {
         await ExecuteADBAsync(num);
         await Task.Delay(10000);
     }

     stoppedMat[num] = null;
     스톱반복횟수[num] = 0;

     findimg.Dispose();
     ScreenMat.Dispose();
     grayImage.Dispose();
     roiImage.Dispose();
     GC.Collect();
 }

 스톱반복횟수[num]++;

}

앱플레이어가 만약 정지되어 있다면 adb 로 연결해서 앱플레어내의 앱을 강제종료 시키고 재실행하는 코드입니다. 이게 왜 렉이 걸릴까요? 2주 정도 생각해보고 여러가지 해봐도 도무지 이해를 못하겠네요.
C# 초보를 도와주세요.

1 Like

Task.Delay 를 모두 지우면 어떤가요?

1 Like

결론만 말씀드리자면, 성능 유닛 테스트를 작성하여 기존 코드와 변경 코드 간 퍼포먼스 비교를 하시는 방법을 추천드립니다.

Home | BenchmarkDotNet

dotnet/BenchmarkDotNet: Powerful .NET library for benchmarking (github.com)

코드를 지속적으로 유지보수하실 계획이시라면, 매 수정이 발생할 때마다 어플리케이션을 실행하셔서 마우스로 성능 테스트를 해야 하며 환경이 달라져도 비슷한 성능을 내는지 확인하기가 어렵습니다.

따라서, 코드 변경마다 성능을 추적해야 할 만큼 퍼포먼스가 중요한 코드라면 BenchmarkDotNet를 따라 테스트 코드를 작성하시길 추천드립니다.

코드에서 논리적인 문제가 아니라 성능 저하 문제의 원인을 찾는 건 대체로 쉽지 않은 경우가 많습니다. 왜냐하면 단일한 이유가 아닌 복합적인 이유로 성능이 떨어질 수도 있기 때문입니다. 이를 명확히 이해하려면 CLR (Common Language Runtime) 의 동작 원리나 IL (Intermediate Language) 코드로 변환되는 형태 또는 비동기 또는 병렬 프로그래밍에 대한 깊은 이해가 필요하게 됩니다.

따라서, 성능 저하의 원인을 추적하기 보다는 이전 코드보다 성능을 저하시킨 변경 코드가 무엇인지 경험적으로 탐색하는 방법이 C# 초보에게 권장되는 방법이라 할 수 있습니다.

하지만 원인을 찾아 수정하는 과정보다 한 줄 한 줄 주석하고 변경하고 프로그램 실행하고 조작하는 일련의 과정이 매우 생산성이 떨어지므로 Benchmark 유닛 테스트를 작성하시는 걸 권고드리는 바입니다.

위와 같은 귀납적 접근 방법으로 원인이 되는 코드를 찾으면, 원인을 분석하여 동작 원리를 학습하시면 좋습니다.

질문에 코드 블럭이 제대로 처리되어 있지 않아, 코드를 파악하기가 어렵습니다. 로직이나 파라미터 이름이 약어로 작성되어 있어 코드 가독성이 떨어져 분석하기 쉽지 않네요… 예를 들어, roiImage 란 무슨 이미지인지 모르겠습니다. Mat2D Matrix 일 걸로 추정되고 이를 CopyTo 하는 방법이 효율이 떨어지는 상황일 수도 있습니다. 일단 Task.Delay가 너무 많아서 성능 저하의 원인일 가능성이 높아 보입니다.

추가 작성

팀 내에서 협업 시, 여러 코드가 병합되어 성능이 떨어졌다면 누가 작성한 코드가 효율을 저하되도록 만든 건지 책임 소재를 두고 언성이 오고 갈 수도 있습니다. 본인이 작성한 코드에 대해 팀원 또는 팀장에게 신뢰를 얻는데, 근거 자료를 제시하거나 비슷한 예제를 찾거나 하는 방법보다 테스트 코드를 작성하는 방법이 제일 생산적입니다.

코드 리뷰해야 하는 입장에서도 테스트 코드가 있으면 코드 리뷰에 들어가는 시간을 줄일 수 있어 효율적입니다.

5 Likes