2017-05-23 4 views
1

장기 실행 백그라운드 작업이 있다고 가정 해 보겠습니다. 각 직업은 약간의 일을하고, 다음 일을 잡고 실행하며, 끝날 때까지 계속됩니다.장기 실행 작업 대 스레드 - 성능

이것은 현재 작업을 사용하여 구현됩니다. 루프 내에서 한 번에 하나의 작업을 실행하는 JobStream이 있습니다. 로드에 따라 한 번에 5 개, 15 개 또는 50 개 스트림을 실행할 수 있습니다.

JobManager

public Task Run(CancellationToken cancellationToken) { 
    var jobTasks = Enumerable 
     .Range(0, _config.BackgroundProcessor.MaximumSimultaneousJobs) 
     .Select(o => JobStream.StartNew(...,() => RunNextJob(cancellationToken), cancellationToken)); 

    return Task.WhenAll(jobTasks); 
} 

작업 열

public static Task StartNew(Func<Task> nextJobRunner, CancellationToken cancellationToken) { 
    var jobStream = new JobStream(nextJobRunner, cancellationToken); 

    return jobStream.Start(); 
} 

private Task Start() { 
    return Task.Run(async() => { 
     do { 
      await _nextJobRunner(); 
     } while (!_cancellationToken.IsCancellationRequested); 
    }); 
} 

내 질문에, 작업은 여기에 좋은 움직임이다되고, 아니면 그냥 스레드에게 옛날 방식을 작성해야합니까? 저는 주로 성과에 관심을 가지고 있고, 또 다른 사람들이 열심히 노력하고 있기 때문에 일자리가 묶이지 않고 독립적으로 일할 수 있도록합니다.

+0

이 작업을 위해서는 Microsoft의 Reactive Framework (NuGet "System.Reactive")를 사용해야합니다. 더 강력하고 간단합니다. – Enigmativity

+0

감사합니다. 감사합니다. –

+0

@ JoshM., 나에게 [이 질문] (https://stackoverflow.com/q/22492383/1768303)을 상기시켰다. – Noseratio

답변

5

정말 Microsoft의 Reactive Framework (NuGet "System.Reactive")를 사용해야합니다. 더 강력하고 간단합니다.

다음은 예입니다 :

void Main() 
{ 
    int number_of_streams = 10; 

    IObservable<int> query = 
     Observable 
      .Range(0, number_of_streams) 
      .Select(stream_number => 
       Observable 
        .Defer(() => Observable.Start(() => nextJob(stream_number))) 
        .Repeat()) 
      .Merge(); 

    IDisposable subscription = 
     query 
      .Subscribe(x => Console.WriteLine(x)); 
} 

public int nextJob(int streamNumber) 
{ 
    Thread.Sleep(10000); 
    return streamNumber; 
} 

이 10 개 동시 스트림을 실행하고 각 스트림에 int nextJob(int streamNumber)를 호출합니다. 나는 각 작업에 대해 10 초의 작업을 시뮬레이트했지만 출력 결과는 매초마다 결과를 산출합니다.

subscription.Dispose()에 전화 할 때까지이 쿼리는 10 개의 스트림에서 영원히 반복되며 모두 중지됩니다.

+0

답변 감사. 나는이 상황에서 Tasks 대 Threads에 관해서는 여전히 궁금하다. –

+0

@ JoshM. - 작업을 수행하십시오. 스레드는 관리하기가 훨씬 더 어렵습니다. – Enigmativity

+0

'Select -> Merge' 대신'SelectMany'를 사용할 수 있습니다. – bradgonesurfing

1

@Enigmativity에서 제공하는 답변이 좋습니다.

그러나 일자리와 스레드 간의 성능 차이에 대한

:

작업이 장기 실행 및 CPU를 많이 사용하는 경우는, 성능 차이는 무시할 수 있습니다.

작업이 오래 실행되지만 CPU를 많이 사용하지 않는 경우 작업이 편리하고 스레드 작성 비용이 절약되므로 작업을 사용하십시오.

작업이 짧으면 TPL 오버 헤드가 단기 실행 작업에 중요하므로 고유 한 대기열과 구식 멀티 스레딩을 사용하십시오.

구식 멀티 스레딩과 비교할 때, 작업은 백그라운드 작업을 실행하는 편리한 방법입니다. 스레드 생성 비용은 절약되지만이 비용은 (수천 개의) 스레드를 많이 생성해야하는 경우에만 중요합니다. 태스크는 큐 및 스케줄링, 결과 및 예외 추적에 약간의 오버 헤드를 추가하지만, 수십만 개를 작성할 때만 중요합니다. 이러한 작업은 진정으로 장기 실행되는 경우에는 해당되지 않습니다. 이렇게 오래 실행되는 많은 작업을 처리해야하는 경우 작업과 스레드 간의 성능 차이를 비교하는 것보다 걱정할 다른 문제가 있습니다.