2009-09-29 3 views
6

Dr Dobbs 사이트에서 오늘 알게되었습니다 http://www.ddj.com/hpc-high-performance-computing/220300055?pgno=3 실의 임 플리 멘 테이션에 관한 좋은 제안입니다. 델파이에서 TThread로 이것을 달성하는 가장 좋은 방법은 무엇입니까? 감사 브라이언델파이에서 쓰레드 수를 프로그래밍하는 법

박사 돕 스는의 ==============에서

===

만들기 멀티 스레딩이 구성! 프로그램에서 사용되는 스레드의 수는 항상 0 (추가 스레드 없음)에서 임의의 수로 구성 가능해야합니다. 이는 최적의 성능을위한 사용자 정의를 허용 할뿐만 아니라 클라이언트 시스템에서 알려지지 않은 경쟁 조건이 발생할 때 좋은 디버깅 도구이자 때로는 생명의 은인임을 입증합니다. 고객이 멀티 스레딩을 해제하여 치명적인 버그를 극복 할 수 있었던 두 가지 이상의 상황을 기억합니다. 이것은 물론 멀티 스레드 파일 I/O에만 적용되는 것은 아닙니다.

는 다음 의사 생각해 (조금 더 작업이 아마 여기에 표시된 것보다 필요합니다하지만)

int CMyThreadManger::AddThread(CThreadObj theTask) 
{ 
    if(mUsedThreadCount >= gConfiguration.MaxThreadCount()) 
     return theTask.Execute(); // execute task in main thread 
    // add task to thread pool and start the thread 
    ... 
} 

이러한 메커니즘은 매우 복잡되지 않습니다,하지만 때로는 매우 효과적입니다. 또한 OpenMP 또는 인텔의 스레드 기반 빌딩 블록과 같은 사전 작성된 스레딩 라이브러리와 함께 사용할 수도 있습니다. 여기에 표시된 측정 값을 고려할 때 구성 가능한 스레드 수를 두 개 이상 포함하는 것이 좋습니다 (예 : 파일 I/O 및 코어 CPU 작업의 경우). 파일 I/O의 기본값은 0이고 CPU 작업의 경우 < 개의 코어 수가 >입니다. 그러나 모든 멀티 스레딩은 분리 가능해야합니다. 보다 정교한 접근법은 멀티 스레드 성능을 테스트하고 자동으로 사용되는 스레드의 수를 설정하는 코드를 포함 할 수도 있고, 다른 작업을 위해 개별적으로 사용될 수도 있습니다.

===================

답변

0

나는 일반적에만 TThread, 큐 또는 스택에서 '노동자 항목을'필요 하나에서 상속 하나 개의 클래스, 더 이상 아이템을 사용할 수 없을 때 일시 중지 시키십시오. 그런 다음 주 프로그램이이 스레드의 인스턴스를 몇 개 만들어서 인스턴스화하고 시작할 수 있는지 결정할 수 있습니다. (이 구성 값 사용).

이 '작업자 항목 대기열'은 작업 항목이 대기 중이거나 스레드가 작업 항목 처리를 마쳤을 때 일시 중단 된 스레드를 다시 시작하거나 필요에 따라 (그리고 제한이 허용하는 경우) 새 스레드를 만들 정도로 똑똑해야합니다. .

+5

스레드를 일시 중단하고 다시 시작할 필요가 없습니다. 각 스레드가 이벤트 나 세마포어를 기다리거나 스레드 메시지 루프와 함께'WaitMessage()'를 사용하십시오 (OLE의 경우 필요할 수 있음). 그래서 [delphi] 아래에있는 주제에 대한 많은 토론이 있습니다.하지만, Embarcadero와 Microsoft devs보다 더 잘 알고 있다고 생각하는 사람들의 주장을 무시하고,'Suspend()'를 사용하여 여러분에게 말하려고합니다. 'Resume()'는 괜찮을 것이다. – mghie

5

나는 추상 클래스 인 TTask를 만들 것이다. 이 클래스는 작업을 실행하기위한 클래스입니다. 메서드 사용 Execute :

type 

    TTask = abstract class 
    protected 
    procedure DoExecute; virtual; abstract; 
    public 
    procedure Execute; 
    end; 

    TTaskThread = class (TThread) 
    private 
    FTask : TTask; 
    public 
    constructor Create(const ATask: TTask); 
    // Assigns FTask and enables thread, free on terminate. 

    procedure Execute; override; // Calls FTask.Execute. 
end; 

Execute 메서드는 스레드 수를 확인합니다. 최대 값에 도달하지 않으면 DoExecute를 호출하는 TTaskThread를 사용하여 스레드를 시작하고 스레드에서 작업을 실행합니다. 최대 값에 도달하면 DoExecute가 직접 호출됩니다.

4

The answer by Gamecat까지는 추상적 인 작업 클래스와 관련해서는 좋지만, 호출 스레드의 작업에 대해서는 DoExecute()을 호출하는 것이 좋지 않다고 생각합니다. 스레딩이 완전히 비활성화되지 않은 한 백그라운드 스레드에 의해 실행될 태스크를 항상 큐에 넣었습니다. 이유는 여기에 있습니다.

Procedure1_WhichTakes200ms; 
Procedure2_WhichTakes400ms; 
Procedure3_WhichTakes200ms; 

이 듀얼 코어 시스템의 활용도를 들어 두 개의 스레드를 실행할 : 당신은 3 개의 독립적 인 CPU 바인딩 프로 시저를 실행하기 위해 필요로하는 곳에

다음 (고안)의 경우를 생각해 보자. 백그라운드 스레드의 수를 1로 제한하므로 메인 스레드의 코어 수는 스레드 수와 같습니다.

이제 첫 번째 절차는 작업자 스레드에서 실행되고 200 밀리 초 후에 완료됩니다. 두 번째 절차는 즉시 시작되고 주 스레드에서 실행됩니다. 단 하나의 구성된 작업자 스레드가 이미 사용 중이며 400 밀리 초 후에 완료됩니다. 그런 다음 마지막 절차는 이미 200 밀리 초 동안 이미 잠 들어 있던 작업자 스레드에서 실행되고 200 밀리 초 후에 완료됩니다. 총 실행 시간은 600 밀리 초이고 그 시간의 2/3은 두 스레드 중 하나만 실제로 의미있는 작업을 수행했습니다.

절차 (작업)를 재정렬 할 수는 있지만 실생활에서는 각 작업의 소요 시간을 미리 알 수 없습니다.

이제 스레드 풀을 사용하는 일반적인 방법을 고려해보십시오. 구성에 따라 풀의 스레드 수를 2 (코어 수)로 제한하고 주 스레드 만 풀에 스레드를 예약 한 다음 모든 작업이 완료 될 때까지 기다립니다. 위의 작업 대기열에서 스레드 1은 첫 번째 작업을 수행하고 스레드 2는 두 번째 작업을 수행합니다. 200 밀리 초가 지나면 첫 번째 작업이 완료되고 첫 번째 작업 스레드가 풀에서 세 번째 작업을 가져옵니다.이 작업은 나중에 비어있게됩니다. 400 밀리 초가 지나면 두 번째와 세 번째 작업이 모두 완료되고 주 스레드는 차단 해제됩니다. 해당 시간의 두 코어에 대해 100 %의로드로 실행을위한 총 시간 400 밀리 초.

적어도 CPU 바인딩 된 스레드의 경우 항상 OS 스케줄러에 대기중인 작업을 수행하는 것이 매우 중요합니다. 주 스레드에서 DoExecute()을 호출하면이를 방해하므로 수행하지 않아야합니다.