Microsoft MVP성태의 닷넷 이야기
닷넷: 2263. C# - Thread가 Task보다 더 빠르다는 어떤 예제(?) [링크 복사], [링크+제목 복사],
조회: 10390
글쓴 사람
정성태 (seongtaejeong at gmail.com)
홈페이지
첨부 파일
 

C# - Thread가 Task보다 더 빠르다는 어떤 예제(?)

아래의 글에 대해,

6 ways to use parallelism with Tasks and Threads in C# .NET
; https://medium.com/@saulodacruz1999/6-ways-to-use-parallelism-with-tasks-and-threads-in-c-net-20c8bbd62102

이런 의견을 다루고 있는데요,

Thread가 Task보다 더 빠르다는 어떤 예제
; https://forum.dotnetdev.kr/t/thread-task/10745

그러니까, 원본 글을 쓴 사람이 11초가 걸린다는 아래의 코드를 보면,

var count = 0;
var anyObject = new object();
UseTasks();

void UseTasks()
{
    var tasks = new List<Task>();

    for (int i = 0; i < 100; i++)
    {
        var task = new Task(() =>
        {
            AnyMethod();
            lock (anyObject) count++;
        });

        task.Start();
        tasks.Add(task);
    }

    Task.WaitAll(tasks.ToArray());
}

void AnyMethod() => Thread.Sleep(1000);

// Time spent: 11 seconds

(Thread로 직접 구현하면 2초가 걸린다고 하는데, 이게 좀 이상하군요, 이론상 1초 정도에 끝납니다. 아마도 EXE 수준에서의 실행 시간을 측정한 것이 아닌가... 합니다.) Task로 구현해 11초가 걸린다고 합니다. 그런데, 사실 이 문제는 Thread나 Task의 비교에서 올 것이 아닙니다. 왜냐하면 둘 다 결국 Thread로 스케줄링이 될 뿐, 저렇게 차이가 나며 실행될 여지가 없기 때문입니다.

그렇다면 왜 저런 결과가 나오는 것일까요?

저건 Task 자체의 문제는 아니고, (Task가 기반을 둔) ThreadPool의 스레드 운영 정책에서 기인합니다. 이에 대해서는 전에도 한 번 설명한 적이 있습니다.

ThreadPool.QueueUserWorkItem의 실행 지연
; https://www.sysnet.pe.kr/2/0/1455

따라서, 100개의 스레드를 쓸 것이라는 가정을 한다면 애당초 그만큼 미리 스레드를 (별다른 조건 없이 빠르게) 준비하도록 다음과 같이 설정해 주면 됩니다.

ThreadPool.SetMinThreads(100, 100);

Stopwatch st = new Stopwatch();
st.Start();
// ...[이하 Task 사용 코드]....
st.Stop();
Console.WriteLine(st.ElapsedMilliseconds); // 출력 결과: 1022

1022ms니까, Task를 사용했어도 1초 내에 거의 마무리가 된 것입니다.




사실, "6 ways to use parallelism with Tasks and Threads in C# .NET" 글의 Task 예제를 각자의 컴퓨터에서 돌려보면 11초가 아닌, 다른 시간이 나올 수 있습니다.

다시 말하지만, 이것은 ThreadPool의 정책으로 인해 미리 만들어 둔 스레드의 수가 문제인 건데요, 가령 제 컴퓨터에서는,

ThreadPool.GetMinThreads(out int workerThreads, out _);
Console.WriteLine($"{workerThreads}"); // 출력 결과: 24

미리 만들어 둔 스레드가 24개이므로 100개의 작업에 나뉘므로 대략 걸리는 시간을 이런 식으로 추측할 수 있습니다.

int expected = (int) Math.Ceiling(100.0f / workerThreads);
Console.WriteLine(expected); // 출력 결과: 5

실제로 (SetMinThreads 호출 없이) 제 컴퓨터에서 Task 예제를 돌리면 (11초가 아닌) 5040ms 정도의 시간이 걸리는 것을 확인할 수 있습니다. (물론, 저런 예측 시간 계산은 스레드풀의 스레드가 증가할 시간 내이기 때문에 거의 정확하게 들어맞은 것입니다. 그렇지 않은 경우라면 중간에 스레드를 늘리기 때문에 예측치가 빗나갈 수 있습니다.)

참고로, 왜 제 컴퓨터에서는 24개의 MinThread가 나왔을까요?

그것은, 24 HT/Core를 갖고 있기 때문입니다. ^^ 그리고 이런 것은 이미 문서에 어느 정도 공개돼 있는 내용입니다.

ThreadPool.GetMinThreads(Int32, Int32) Method
; https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool.getminthreads

By default, the minimum number of threads is set to the number of processors on a system. When the minimum is reached, the thread pool can create additional threads in that category or wait until some tasks complete




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 5/22/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 46  47  48  49  50  51  52  53  54  55  56  57  58  59  [60]  ...
NoWriterDateCnt.TitleFile(s)
12501정성태1/21/202119332.NET Framework: 1015. .NET 5부터 HTTP/1.1, 2.0 선택을 위한 HttpVersionPolicy 동작 방식파일 다운로드1
12500정성태1/21/202120694.NET Framework: 1014. ASP.NET Core(Kestrel)의 HTTP/2 지원 여부파일 다운로드1
12499정성태1/20/202122134.NET Framework: 1013. .NET Core Kestrel 호스팅 - 포트 변경, non-localhost 접속 지원 및 https 등의 설정 변경 [1]파일 다운로드1
12498정성태1/20/202118710.NET Framework: 1012. .NET Core Kestrel 호스팅 - 비주얼 스튜디오의 Kestrel/IIS Express 프로파일 설정
12497정성태1/20/202124192.NET Framework: 1011. C# - OWIN Web API 예제 프로젝트 [1]파일 다운로드2
12496정성태1/19/202120084.NET Framework: 1010. .NET Core 콘솔 프로젝트에서 Kestrel 호스팅 방법 [1]
12495정성태1/19/202122273웹: 40. IIS의 HTTP/2 지원 여부 - h2, h2c [1]
12494정성태1/19/202122022개발 환경 구성: 522. WSL 2 인스턴스와 호스트 측의 Hyper-V에 운영 중인 VM과 네트워크 연결을 하는 방법 [2]
12493정성태1/18/202120143.NET Framework: 1009. .NET 5에서의 네트워크 라이브러리 개선 (1) - HTTP 관련 [1]파일 다운로드1
12492정성태1/17/202118493오류 유형: 695. ASP.NET 0x80131620 Failed to bind to address
12491정성태1/16/202119640.NET Framework: 1008. 배열을 반환하는 C# COM 개체의 메서드를 C++에서 사용 시 메모리 누수 현상 [1]파일 다운로드1
12490정성태1/15/202118373.NET Framework: 1007. C# - foreach에서 열거 변수의 타입을 var로 쓰면 object로 추론하는 문제 [1]파일 다운로드1
12489정성태1/13/202121845.NET Framework: 1006. C# - DB에 저장한 텍스트의 (이모티콘을 비롯해) 유니코드 문자가 '?'로 보인다면? [1]
12488정성태1/13/202119634.NET Framework: 1005. C# - string 타입은 shallow copy일까요? deep copy일까요? [2]파일 다운로드1
12487정성태1/13/202118042.NET Framework: 1004. C# - GC Heap에 위치한 참조 개체의 주소를 알아내는 방법파일 다운로드1
12486정성태1/12/202121409.NET Framework: 1003. x64 환경에서 참조형의 기본 메모리 소비는 얼마나 될까요? [1]
12485정성태1/11/202120190Graphics: 38. C# - OpenCvSharp.VideoWriter에 BMP 파일을 1초씩 출력하는 예제 [2]파일 다운로드1
12484정성태1/9/202123236.NET Framework: 1002. C# - ReadOnlySequence<T> 소개파일 다운로드1
12483정성태1/8/202118982개발 환경 구성: 521. dotPeek - 훌륭한 역어셈블 소스 코드 생성 도구
12482정성태1/8/202120838.NET Framework: 1001. C# - 제네릭 타입/메서드에서 사용 시 경우에 따라 CS8377 컴파일 에러
12481정성태1/7/202120643.NET Framework: 1000. C# - CS8344 컴파일 에러: ref struct 타입의 사용 제한 메서드파일 다운로드1
12480정성태1/6/202123342.NET Framework: 999. C# - ArrayPool<T>와 MemoryPool<T> 소개파일 다운로드1
12479정성태1/6/202120716.NET Framework: 998. C# - OWIN 예제 프로젝트 만들기
12478정성태1/5/202124579.NET Framework: 997. C# - ArrayPool<T> 소개파일 다운로드1
12477정성태1/5/202125377기타: 79. github 코드 검색 방법 [1]
12476정성태1/5/202120098.NET Framework: 996. C# - 닷넷 코어에서 다른 스레드의 callstack을 구하는 방법파일 다운로드1
... 46  47  48  49  50  51  52  53  54  55  56  57  58  59  [60]  ...