[multithreading] 멀티 스레딩 : 코어보다 더 많은 스레드의 요점은 무엇입니까?

멀티 코어 컴퓨터의 요점은 여러 스레드를 동시에 실행할 수 있다는 것입니다. 이 경우 쿼드 코어 머신을 사용하는 경우 한 번에 4 개 이상의 스레드가 실행되는 시점은 무엇입니까? 그들은 단지 서로에게서 시간을 훔치지 않을 것입니까 (CPU 리소스)?



답변

대답은 스레드의 목적을 중심으로 진행되는데, 이는 병렬 처리입니다. 한 번에 여러 개의 개별 실행 라인을 실행하는 것입니다. ‘이상적인’시스템에서는 코어 당 하나의 스레드가 실행됩니다 (중단 없음). 실제로는 그렇지 않습니다. 4 개의 코어와 4 개의 작업 스레드가 있어도 프로세스 및 스레드는 다른 프로세스 및 스레드에 대해 지속적으로 전환됩니다. 최신 OS를 실행하는 경우 모든 프로세스에는 하나 이상의 스레드가 있으며 많은 스레드가 있습니다. 이 모든 프로세스는 한 번에 실행됩니다. 아마도 지금 당신의 컴퓨터에서 수백 개의 스레드가 모두 실행 중일 것입니다. 스레드가 시간을 도난 당하지 않고 스레드가 실행되는 상황은 없습니다. ( 실시간으로 실행 된다면실시간 OS를 사용하거나 Windows에서도 실시간 스레드 우선 순위를 사용하십시오. 그러나 드물다.)

그 배경으로 대답은 그렇습니다. 그렇습니다. 실제 4 코어 머신에서 4 개 이상의 스레드는 각각의 스레드가 100 % CPU를 필요로하는 경우에만 ‘서로 시간을 훔치는’상황을 제공 할 수 있습니다 . 스레드가 100 % 작동하지 않으면 (UI 스레드가 작동하지 않거나 약간의 작업을 수행하거나 다른 작업을 기다리는 스레드) 실제로 예약중인 다른 스레드가 좋은 상황입니다.

실제로는 그보다 더 복잡합니다.

  • 한 번에 모두 완료해야하는 5 비트 작업이있는 경우 어떻게합니까? 4 개를 실행 한 다음 5 번째를 실행하는 것보다 한 번에 모두 실행하는 것이 더 합리적입니다.

  • 스레드가 실제로 100 % CPU를 필요로하는 경우는 드 rare니다. 예를 들어, 디스크 또는 네트워크 I / O를 사용하는 순간, 아무 쓸모없는 작업을 기다리는 데 시간이 걸릴 수 있습니다. 이것은 매우 일반적인 상황입니다.

  • 실행해야하는 작업이있는 경우 일반적인 메커니즘 중 하나는 스레드 풀을 사용하는 것입니다. 코어와 동일한 수의 스레드를 갖는 것이 타당 할 수 있지만 .Net 스레드 풀에는 프로세서 당 최대 250 개의 스레드가 있습니다 . 나는 그들이 왜 이것을하는지 확실하지 않지만, 내 추측은 스레드에서 실행되도록 주어진 작업의 크기와 관련이 있습니다.

따라서 : 도둑질 시간은 나쁜 일이 아니며 (실제로 도난 당하지도 않습니다 : 시스템이 작동하는 방식입니다.) 스레드가 수행 할 작업의 종류에 따라 멀티 스레드 프로그램을 작성하십시오 .CPU가 아닐 수도 있습니다 -경계. 프로파일 링 및 측정에 따라 필요한 스레드 수를 파악하십시오. 스레드보다는 작업 또는 작업의 관점에서 생각하는 것이 더 유용 할 수 있습니다. 작업 개체를 작성하고 실행할 풀에 제공하십시오. 마지막으로, 프로그램이 성능에 중요하지 않으면 너무 걱정하지 마십시오. 🙂


답변

스레드가 존재한다고해서 항상 스레드가 실행되고있는 것은 아닙니다. 스레드의 많은 응용 프로그램은 스레드가 무언가를 수행 할 시간이 될 때까지 일부 스레드가 잠기 게합니다.

기본적으로 스레드는 다른 작업의 진행 상황을 알 필요없이 서로 독립적으로 작동 할 수있는 개별 작업입니다. 동시에 실행할 수있는 것보다 더 많은 것을 가질 수 있습니다. 그들은 때때로 서로 뒤에 줄을 서서 기다려야 할지라도 편의상 여전히 유용합니다.


답변

요점은 스레드 수가 코어 수를 초과 할 때 실제 속도 향상을 얻지 못하더라도 스레드를 사용하여 상호 의존성이 없어야하는 논리 조각을 분리 할 수 ​​있다는 것입니다.

약간 복잡한 응용 프로그램에서도 단일 스레드를 사용하면 모든 작업을 신속하게 수행하여 코드의 ‘흐름’을 해시합니다. 단일 스레드는 대부분의 시간을 이것을 폴링하고,이를 확인하고, 필요에 따라 조건부로 루틴을 호출하며, 사소한 조악한 것을보기가 어려워집니다.

스레드를 작업 전용으로 사용하여 개별 스레드를보고 해당 스레드가 수행중인 작업을 확인할 수있는 경우와 비교하십시오. 예를 들어, 하나의 스레드가 소켓에서 입력 대기를 차단하고 스트림을 메시지로 구문 분석하고 메시지를 필터링하며 유효한 메시지가 나타나면 다른 작업자 스레드로 전달합니다. 작업자 스레드는 여러 다른 소스의 입력에서 작동 할 수 있습니다. 이들 각각에 대한 코드는 별도의 조치가 없는지 명시 적으로 확인할 필요없이 깨끗하고 목적이있는 흐름을 나타냅니다.

이러한 방식으로 작업을 분할하면 응용 프로그램이 운영 체제에 의존하여 CPU로 다음에 수행 할 작업을 예약 할 수 있으므로 응용 프로그램 내에서 차단할 수있는 항목과 처리 할 수있는 대상에 대한 조건부 검사를 명시 적으로 수행 할 필요가 없습니다.


답변

스레드가 자원을 기다리고있는 경우 (예 : RAM에서 레지스터, 디스크 I / O, 네트워크 액세스로 값로드, 새 프로세스 시작, 데이터베이스 쿼리 또는 사용자 입력 대기 등) 프로세서는 리소스를 사용할 수있게되면 첫 번째 스레드로 돌아갑니다. CPU가 유휴 상태가 아닌 수백만 개의 작업을 수행 할 수 있기 때문에 CPU가 유휴 시간을 줄입니다.

하드 드라이브에서 데이터를 읽어야하는 스레드를 고려하십시오. 2014 년에 일반적인 프로세서 코어는 2.5GHz에서 작동하며 사이클 당 4 개의 명령을 실행할 수 있습니다. 사이클 시간이 0.4 ns 인 프로세서는 나노 초당 10 개의 명령을 실행할 수 있습니다. 일반적인 기계식 하드 드라이브 탐색 시간은 약 10 밀리 초이므로 프로세서는 하드 드라이브에서 값을 읽는 데 걸리는 시간에 1 억 개의 명령을 실행할 수 있습니다. 하이브리드 섹션에서 순차적 읽기 또는 읽기를위한 데이터 대기 시간이 몇 배 더 빠를 수 있으므로 작은 캐시 (4MB 버퍼)가있는 하드 드라이브와 몇 GB의 스토리지가있는 하이브리드 드라이브의 성능이 크게 향상 될 수 있습니다.

프로세서 코어는 스레드간에 전환 할 수 있으며 (스레드 일시 중지 및 재개 비용은 약 100 클럭주기) 첫 번째 스레드는 대기 시간이 긴 입력 (레지스터 (1 클럭) 및 RAM (5 나노초)보다 비싼 항목)을 기다립니다. 디스크 I / O, 네트워크 액세스 (대기 시간 250ms), CD 또는 느린 버스에서 데이터 읽기 또는 데이터베이스 호출 코어보다 많은 스레드가 있으면 대기 시간이 긴 작업이 해결되는 동안 유용한 작업을 수행 할 수 있습니다.

CPU에는 스레드 스케줄러가있어 각 스레드에 우선 순위를 지정하고 스레드를 휴면 상태로 설정 한 후 사전 결정된 시간 후에 다시 시작할 수 있습니다. 스레 싱을 줄이는 것은 스레드 스케줄러의 작업입니다. 각 스레드가 다시 잠자기 전에 100 개의 명령 만 실행하면 발생합니다. 스레드 전환의 오버 헤드는 프로세서 코어의 총 유용한 처리량을 줄입니다.

이러한 이유로 문제를 합리적인 수의 스레드로 나누고 싶을 수 있습니다. 행렬 곱셈을 수행하기위한 코드를 작성하는 경우 출력 행렬에서 셀당 하나의 스레드를 작성하는 것이 과도 할 수있는 반면 , 출력 행렬에서 행당 또는 행당 n 개의 행을 작성하면 스레드 작성, 일시 정지 및 재개에 드는 오버 헤드 비용이 줄어들 수 있습니다.

이것이 분기 예측이 중요한 이유이기도합니다. RAM에서 값을로드해야하는 if 문이 있지만 if 및 else 문의 본문은 이미 레지스터에로드 된 값을 사용하는 경우 프로세서는 조건이 평가되기 전에 하나 또는 두 개의 분기를 실행할 수 있습니다. 조건이 반환되면 프로세서는 해당 분기의 결과를 적용하고 다른 분기를 버립니다. 잠재적으로 쓸모없는 작업을 수행하는 것이 다른 스레드로 전환하는 것보다 낫습니다.

우리는 고속 단일 코어 프로세서에서 멀티 코어 프로세서로 이동함에 따라 칩 설계는 다이 당 더 많은 코어를 크 래밍하고 코어 간의 온칩 리소스 공유 개선, 분기 예측 알고리즘 개선, 스레드 전환 오버 헤드 개선, 더 나은 스레드 스케줄링.


답변

위의 답변 대부분은 성능과 동시 작동에 대해 이야기합니다. 나는 다른 각도에서 이것에 접근 할 것입니다.

간단한 터미널 에뮬레이션 프로그램을 예로 들어 봅시다. 다음을 수행해야합니다.

  • 원격 시스템에서 들어오는 문자를보고 표시합니다
  • 키보드에서 나오는 물건을보고 원격 시스템으로 보냅니다.

(실제 터미널 에뮬레이터는 입력 한 내용을 디스플레이에 에코하는 것을 포함하여 더 많은 작업을 수행하지만 지금은 그 내용을 전달할 것입니다.)

이제 다음 의사 코드에 따라 리모콘에서 읽는 루프가 간단합니다.

while get-character-from-remote:
    print-to-screen character

키보드를 모니터링하고 전송하는 루프도 간단합니다.

while get-character-from-keyboard:
    send-to-remote character

그러나 문제는이 작업을 동시에 수행해야한다는 것입니다. 스레딩이 없으면 코드는 다음과 같이 보입니다.

loop:
    check-for-remote-character
    if remote-character-is-ready:
        print-to-screen character
    check-for-keyboard-entry
    if keyboard-is-ready:
        send-to-remote character

통신의 실제 복잡성을 고려하지 않은이 의도적으로 단순화 된 예에서도 논리는 매우 난독 화됩니다. 그러나 스레딩을 사용하면 단일 코어에서도 두 개의 의사 코드 루프가 논리를 인터레이스하지 않고 독립적으로 존재할 수 있습니다. 두 스레드는 대부분 I / O 바운드이기 때문에 엄밀히 말하면 통합 루프보다 CPU 리소스가 더 낭비 되더라도 CPU에 많은 부하를주지 않습니다.

물론 실제 사용은 위의 것보다 더 복잡합니다. 그러나 애플리케이션에 더 많은 관심을 가짐에 따라 통합 루프의 복잡성이 기하 급수적으로 증가합니다. 논리는 점점 더 세분화되고 상태 머신, 코 루틴 등과 같은 기술을 사용하여 일을 관리해야합니다. 관리는 가능하지만 읽을 수는 없습니다. 스레딩은 코드를 더 읽기 쉽게 유지합니다.

그렇다면 왜 스레딩을 사용하지 않습니까?

작업이 I / O 바운드 대신 CPU 바운드 인 경우 스레딩은 실제로 시스템 속도를 저하시킵니다. 성능이 저하됩니다. 많은 경우에 많이 있습니다. ( “스 래싱 (Thrashing)”은 CPU 바운드 스레드를 너무 많이 삭제하면 일반적인 문제입니다. 스레드 자체의 내용을 실행하는 것보다 활성 스레드를 변경하는 데 더 많은 시간을 소비하게됩니다. 또한 위의 논리 중 하나는 매우 간단합니다. 저는 단순하고 비현실적인 예제를 고의적으로 선택했습니다. 화면에 입력 된 내용을 에코하려면 공유 리소스 잠금을 도입하면서 새로운 상처를 입게됩니다. 공유 리소스가 하나만 있으면 별 문제가되지 않지만 공유 할 리소스가 많을수록 더 큰 문제가되기 시작합니다.

결국 스레딩은 많은 것들에 관한 것입니다. 예를 들어, 일부 사람들이 이미 말했듯이 I / O 바운드 프로세스를 전반적으로 덜 효율적으로 만드는 것이 중요합니다. 또한 논리를 쉽게 따르기위한 것입니다 (공유 상태를 최소화 한 경우에만). 그것은 많은 것들에 관한 것이며, 사례별로 장점이 장점보다 큰지 결정해야합니다.


답변

하드웨어에 따라 계산 속도를 높이기 위해 스레드를 확실히 사용할 수 있지만 주요 용도 중 하나는 사용자에게 친숙한 이유로 한 번에 둘 이상의 작업을 수행하는 것입니다.

예를 들어, 백그라운드에서 일부 처리를 수행해야하고 UI 입력에 계속 응답해야하는 경우 스레드를 사용할 수 있습니다. 스레드가 없으면 많은 처리를 시도 할 때마다 사용자 인터페이스가 중단됩니다.

이 관련 질문도 참조하십시오 : 스레드의 실제 사용


답변

이상적인 숫자는 CPU 당 하나의 스레드라는 @kyoryu의 주장에 강력히 동의하지 않습니다.

이런 식으로 생각하십시오. 왜 다중 처리 운영 체제가 있습니까? 대부분의 컴퓨터 기록에서 거의 모든 컴퓨터에는 하나의 CPU가있었습니다. 그러나 1960 년대부터 모든 “실제”컴퓨터에는 다중 처리 (일명 다중 태스킹) 운영 체제가있었습니다.

여러 프로그램을 실행하여 하나는 실행할 수 있고 다른 프로그램은 IO와 같은 것으로 차단합니다.

NT 이전의 Windows 버전이 멀티 태스킹인지에 대한 인수를 따로 설정할 수 있습니다. 그 이후로 모든 실제 OS에는 멀티 태스킹이있었습니다. 일부는 사용자에게 노출시키지 않지만 어쨌든 핸드폰 라디오 청취, GPS 칩과 대화, 마우스 입력 수락 등과 같은 작업을 수행합니다.

스레드는 좀 더 효율적인 작업입니다. 작업, 프로세스 및 스레드간에 근본적인 차이는 없습니다.

CPU는 끔찍한 일이므로 끔찍한 일을 할 준비가되어 있어야합니다.

대부분의 절차 적 언어 인 C, C ++, Java 등에서는 적절한 스레드 안전 코드를 작성하는 것이 많은 작업이라는 데 동의합니다. 오늘날 시중에 6 개의 코어 CPU가 있고 멀지 않은 16 개의 코어 CPU가 있기 때문에 멀티 스레딩이 점점 더 중요한 요구 사항이기 때문에 사람들은 이러한 오래된 언어에서 벗어날 것으로 기대합니다.

@kyoryu와의 의견 차이는 IMHO 일 뿐이며 나머지는 사실입니다.