멀티 코어 컴퓨터의 요점은 여러 스레드를 동시에 실행할 수 있다는 것입니다. 이 경우 쿼드 코어 머신을 사용하는 경우 한 번에 4 개 이상의 스레드가 실행되는 시점은 무엇입니까? 그들은 단지 서로에게서 시간을 훔치지 않을 것입니까 (CPU 리소스)?
멀티 코어 컴퓨터의 요점은 여러 스레드를 동시에 실행할 수 있다는 것입니다. 이 경우 쿼드 코어 머신을 사용하는 경우 한 번에 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 일 뿐이며 나머지는 사실입니다.
임의의 수의 요청을 처리해야하는 웹 서버를 상상해보십시오. 그렇지 않으면 인터넷을 통해 응답을 보내는 것을 포함하여 다른 모든 요청이 완료 될 때까지 각각의 새 요청이 대기해야하기 때문에 요청을 병렬로 제공해야합니다. 이 경우 대부분의 웹 서버는 일반적으로 제공하는 요청 수보다 코어 수가 적습니다.
또한 서버 개발자가 더 쉽게 만들 수 있습니다. 요청을 처리하는 스레드 프로그램 만 작성하면되며 여러 요청 저장, 요청 순서 등을 생각할 필요가 없습니다.
많은 스레드가 잠 들어 사용자 입력, I / O 및 기타 이벤트를 기다립니다.
스레드는 UI 응용 프로그램의 응답 성을 도울 수 있습니다. 또한 스레드를 사용하여 코어에서 더 많은 작업을 수행 할 수 있습니다. 예를 들어, 단일 코어에서 하나의 스레드가 IO를 수행하고 다른 스레드가 일부 계산을 수행하도록 할 수 있습니다. 단일 스레드 인 경우 IO가 완료 될 때까지 코어가 유휴 상태 일 수 있습니다. 꽤 높은 수준의 예제이지만 스레드를 사용하면 CPU를 조금 더 세게 두드리는 데 확실히 사용할 수 있습니다.
프로세서 또는 CPU는 시스템에 연결된 물리적 칩입니다. 프로세서는 여러 개의 코어를 가질 수 있습니다 (코어는 명령을 실행할 수있는 칩의 일부입니다). 코어는 여러 스레드를 동시에 실행할 수있는 경우 운영 체제에 여러 가상 프로세서로 나타날 수 있습니다 (스레드는 단일 명령 시퀀스 임).
프로세스는 응용 프로그램의 다른 이름입니다. 일반적으로 프로세스는 서로 독립적입니다. 한 프로세스가 종료되면 다른 프로세스도 종료되지 않습니다. 프로세스가 통신하거나 메모리 또는 I / O와 같은 리소스를 공유 할 수 있습니다.
각 프로세스에는 별도의 주소 공간과 스택이 있습니다. 프로세스는 여러 스레드를 포함 할 수 있으며 각 스레드는 동시에 명령을 실행할 수 있습니다. 프로세스의 모든 스레드는 동일한 주소 공간을 공유하지만 각 스레드에는 자체 스택이 있습니다.
이러한 정의와 이러한 기본 사항을 사용한 추가 연구를 통해 이해하는 데 도움이되기를 바랍니다.
스레드의 이상적인 사용법은 실제로 코어 당 하나씩입니다.
그러나 비동기 / 비 차단 IO를 독점적으로 사용하지 않으면 어느 시점에서 IO에서 스레드가 차단되어 CPU를 사용하지 않을 가능성이 높습니다.
또한 일반적인 프로그래밍 언어를 사용하면 CPU 당 1 개의 스레드를 사용하기가 다소 어렵습니다. 동시성 (예 : Erlang)을 중심으로 설계된 언어를 사용하면 추가 스레드를 더 쉽게 사용할 수 없습니다.
일부 API를 설계하는 방법은, 당신은하지 선택의 여지가 있지만 (차단 작업과 무엇이든)을 별도의 스레드에서 실행할 수 있습니다. 예를 들어 Python의 HTTP 라이브러리 (AFAIK)가 있습니다.
일반적으로 이것은 큰 문제는 아니지만 (문제가있는 경우 OS 또는 API는 대체 비동기 작동 모드와 함께 제공되어야합니다 :) select(2)
, 아마도 I / 대기 중 스레드가 잠들 것임을 의미하기 때문에 O 완료 뭔가 무거운 계산을하고있는 경우 반면에, 당신은 이 말보다 별도의 스레드에 넣어의 GUI 스레드 (당신은 수동 멀티플렉싱을 즐길 제외).
나는 이것이 좋은 대답이 많은 매우 오래된 질문이라는 것을 알고 있지만 현재 환경에서 중요한 것을 지적하려고 여기 있습니다.
멀티 스레딩을위한 응용 프로그램을 디자인하려는 경우 특정 하드웨어 설정을 디자인하지 않아야합니다. CPU 기술은 수년 동안 매우 빠르게 발전해 왔으며 코어 수는 꾸준히 증가하고 있습니다. 스레드가 4 개만 사용되도록 의도적으로 응용 프로그램을 설계하는 경우 잠재적으로 8 코어 시스템 (예를 들어)으로 제한됩니다. 이제는 20 코어 시스템도 시판되고 있으므로 이러한 디자인은 확실히 좋은 것보다 더 큰 피해를줍니다.
첫 번째 추측에 대한 응답으로, 멀티 코어 머신은 단일 프로세스의 여러 스레드뿐만 아니라 여러 프로세스를 동시에 실행할 수 있습니다.
첫 번째 질문에 대한 답변 : 여러 스레드의 요점은 일반적으로 하나의 응용 프로그램 내에서 여러 작업을 동시에 수행하는 것입니다. 인터넷상의 전형적인 예는 메일을 보내고받는 이메일 프로그램과 페이지 요청을 받고 보내는 웹 서버입니다. (Windows와 같은 시스템을 하나의 스레드 만 또는 하나의 프로세스 만 실행하도록 축소하는 것은 본질적으로 불가능합니다. Windows 작업 관리자를 실행하면 일반적으로 긴 활성 프로세스 목록이 표시되며,이 중 다수는 다중 스레드를 실행합니다. )
두 번째 질문에 대한 답변 : 대부분의 프로세스 / 스레드는 CPU 바운드가 아니며 (즉, 지속적으로 실행되고 중단되지 않음) 대신 I / O가 끝날 때까지 자주 중지하고 기다립니다. 대기 중에 다른 프로세스 / 스레드는 대기 코드에서 "스틸 링"없이 (단일 코어 시스템에서도) 실행될 수 있습니다.
스레드는 일련의 작업처럼 간단하게 코드를 작성할 수있게하는 추상화로, 코드가 다른 코드와 인터레이스되어 실행되거나 IO를 기다리거나 다른 스레드의 대기를 대기하는 것을 알 수 있습니다. 이벤트 또는 메시지.
요점은 대다수의 프로그래머가 상태 머신을 설계하는 방법을 이해하지 못한다는 것입니다. 모든 것을 자체 스레드에 넣을 수 있기 때문에 프로그래머는 다른 진행중인 계산의 상태를 효율적으로 표현하는 방법에 대해 생각하지 않아도 중단되고 나중에 다시 시작할 수 있습니다.
예를 들어, CPU를 많이 사용하는 작업 인 비디오 압축을 고려하십시오. GUI 도구를 사용하는 경우 인터페이스가 응답 상태로 유지되기를 원할 것입니다 (진행률 표시, 요청 취소에 대한 응답, 창 크기 조정 등). 따라서 한 번에 큰 단위 (하나 이상의 프레임)를 처리하고 UI와 별도로 자체 스레드에서 실행하도록 인코더 소프트웨어를 설계합니다.
물론 진행중인 인코딩 상태를 저장하여 프로그램을 종료하여 리소스를 많이 사용하는 게임을 재부팅하거나 재생할 수 있다는 것을 알게되면 처음. 또는 OS에 대한 완전히 새로운 프로세스 동면 문제를 엔지니어링하기로 결정하여 개별 앱을 디스크에 일시 중지하고 다시 시작할 수 있습니다.