9

복잡한 계산 알고리즘을 구축했습니다. 완료하는 데는 꽤 시간이 걸리고 응용 프로그램이 응답 성을 유지하는지 확인하려고합니다. 너 뭐하니?

  • A. async / await를 사용하십시오.
  • B. 코드를 동 기적으로 실행하십시오.
  • C. Task.Run을 사용하십시오.
  • D. BackgroundWorker를 사용하십시오.

대답은 C입니다.하지만 누군가 A)가 틀렸다고 설명 할 수 있습니까? 질문은 복잡한 알고리즘이 CPU에 묶여 있다고 말하지 않기 때문입니다. 만약 CPU가 바운드라면, 우리는 Tasks를 사용해야 할 것입니다. (나는 그 태스크가 완료 될 때까지 현재의 쓰레드가 일시 중지되도록 도와 주지만, 너무 잘 이해하지 못합니다.) 또한 async / await를 사용할시기를 결정하고 작업을 사용하는 방법을 설명하십시오.


  • 틀린 이분법; 대답은 A와 C입니다. ASP.NET에서 대답은 B입니다. - Stephen Cleary

3 답변


3

너 뭐하니?

A. async / await를 사용하십시오.

B. 코드를 동 기적으로 실행하십시오.

C. Task.Run을 사용하십시오.

D. BackgroundWorker를 사용하십시오.

그만큼async/awaitC #5.0의 기능은 비동기 코드를 동기식 코드를 작성하는 것처럼 "쉽게"만들 수 있도록 구현되었습니다. WinAPI를 살펴보면 거의 모든 비동기 끝점이 완전 비동기 API를 노출한다는 것을 알 수 있습니다. 즉,실이 없다.. 더 자세히 살펴보면 같은 엔드 포인트가I / O 경계작업.

귀하의 알고리즘을 가정하면CPU 바운드, 여러 프로세서에서 효과적으로 계산할 수있는 방식으로 작성됩니다 (예 : 알고리즘에 동기화가 필요한 공유 상태가 없음).작업 병렬 라이브러리.NET 4.0에 도입되었습니다. TPL은 다중 프로세서 환경에서 작업을 균등하게 오프로드하려고 시도하는 ThreadPool에 대한 추상화를 제공합니다.

그만큼await키워드는기다리고있는object : 객체가GetAwaiter방법. 당신은await당신이 기다릴 수있는 것을 사용하고있을 때 그 일이 그 일을 끝내면 다시 시작하기를 원할 때. 에이Task기다릴 수있는 패턴을 구현하고 장래에 완료 될 작업 단위를 설명하는 데 사용됩니다. 당신이 사용할 수있는Task.Runawait, 작업 스레드에서 작업 단위를 오프로드하려는 경우그 작업이 끝날 때까지 호출 메소드에 제어권을 되 돌린다..

여러 프로세서에서 CPU 바운드 작업을 디스패치하는 또 다른 방법은Parallel노출하는 클래스Parallel.ForParallel.ForEach.

참고로,BackgroundWorker배경 스레드에서 작업을 오프로드하는 데 사용할 수도 있습니다. 그것은추천 된.NET 4.0이 발표 된 이래로 TPL을 사용했다.

결론을 맺으려면 작업 병렬 라이브러리를 사용하여 작업을 백그라운드 스레드로 오프로드하는 것이 좋습니다. 귀하는 이들을 함께 사용할 수 있습니다.Parallel라이브러리를 사용하여 알고리즘의 병렬 처리를 극대화하십시오. 그렇게 한 후에,코드 테스트하기여러 스레드를 사용하는 오버 헤드가 알 고를 동 기적으로 실행하는 데 걸리는 시간보다 중요하지 않은지 확인하십시오.

편집하다

Stephan이 의견에서 언급했듯이,Parallel.ForEachTask.Run백그라운드 스레드 내에서 병렬 루프를 오프로드하는 방법 :

var task = Task.Run(() => Parallel.ForEach(.. //Loop here));


  • 또한 접근법을 결합하는 것이 유용 할 수 있습니다.await Task.Run(() => Parallel.ForEach(...))UI가 비동기로 처리하는 백그라운드 스레드에 대해 병렬 작업을 수행합니다. - Stephen Cleary

2

나는 "계산"이 다른 정보가 없을 때 CPU 바운드 알고리즘을 의미한다고 가정합니다. 알고리즘이 IO 바인딩 인 경우 비동기 / 대기가 허용 될뿐만 아니라 정답입니다.


  • 그것은 사실입니다. 물론 Dispatcher 접근법을 사용할 수 있습니다. - Stilgar
  • @DimitarDimitrov, 사용중인 경우Task.Run, 전달 된 델리게이트는 UI 스레드가 아닌 다른 스레드에서 실행될 가능성이 높습니다.귀하의 UI는 반응 형으로 유지 될 것입니다.어떤 경우 에든 작업 완료를 막지 못하는 경우Wait()또는Result. 작업 완료를 처리하고 호출 한 스레드와 통신하는 방법Task.Run그러나 우선, 당신에게 달려 있습니다 : 당신은await, 또는 적절한 작업 연속 작업을 사용할 수 있습니다TaskScheduler, 또는 원래 SynchronizationContext를 명시 적으로 캡처하여 대리자 내에서 다시 게시 할 수 있습니다. - Kirill Shlenskiy
  • (계속) 또는 다음을 사용할 수 있습니다.Dispatcher.Invoke또는Control.Invoke, 또는 자신 만의 AsyncEnumerator를 롤 할 수 있습니다 (blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx). 요점은 약 백만 가지 방법이 있다는 것입니다.async/await모든 사람의 마음에 가장 먼저 떠오르는 것이라 할지라도, 그 중 하나가 될 수 있습니다. - Kirill Shlenskiy
  • @KirillShlenskiy 물론, 당신은 100 % 맞습니다. 동의합니다 (비록 약간의 페트 닉이지만).하지만 질문은 여전히 가비지라고합니다. (IMHO). - Dimitar Dimitrov
  • @DimitarDimitrov, 동의했다. - Kirill Shlenskiy

1

질문은 당신이 동기식으로 프로그램 된 알고리즘을 가지고 있다고 가정합니다. 질문은 이것이 CPU에 묶여 있음을 모호하게 암시하는 '계산'이라고 언급합니다. 또한 알고리즘이 동 기적으로 작성된다는 것을 모호하게 의미합니다. 예 :

public int CalculateStuff() {
     ....
}

내가 고려해야 할 것은이 메소드에 비동기 대응을 만드는 것이다.

public async Task<int> CalculateStuffAsync() {
      return await Task.Run(() => CalculateStuff());
}

그런 다음 사용자 인터페이스에서

LoadingIndicator.IsEnabled = true;
ResultTextBox.Text = await CalculateStuffAsync();
LoadingIndicator.IsEnabled = false;

따라서 정답은 아마 A와 C 둘 다가 될 것이다. 어쨌든 그 질문은 너무 확고하여 어떤 확고한 결론을 도출하지 못한다.


  • @DimitarDimitrov가 동의합니다. B를 제외한 모든 것이 기술적으로 유효합니다. - Bas
  • 대중에게 제공하는 @BasBrekelmansxxxAsyncCPU 바운드 작업에 대한 래퍼는 디자인이 좋지 않습니다. 호출자가 줄 바꿈 할 수 없다는 점CalculateStuff...에서Task.Run필요하다면. 또한 다음을 고려하십시오.CalculateStuffAsync().Wait(). 없이ConfigureAwait(false)교착 상태 버그가 발생했습니다. 교착 상태 버그는async방법, 거의 제로 이익을 위해. - Kirill Shlenskiy
  • @DimitarDimitrov, 제 말을 들어주지 마십시오. null이 아닌 것을 설치하는 응용 프로그램에서 코드 비트를 실행하십시오.SynchronizationContext(즉, Windows Forms / WPF) 무엇이 발생하는지 확인하십시오. 이것은 귀하의await원래 상태로 전환해야합니다.SynchronizationContext비동기 작업의 결과가 반환 될 수 있습니다. 스레드를 통해 차단하는 경우Task.Wait쓰레드가 작업을 기다리면서 바쁠 것이기 때문에 결코 바뀌지 않을 것입니다. 장군. 테이크 아웃async/await작업을 직접 반환하면 해결됩니다. - Kirill Shlenskiy
  • (또는 사용ConfigureAwait(false)명백하게) - Kirill Shlenskiy
  • @DimitarDimitrov, 문제 없음; 답장을 잘못 처리 한 것에 대해 사과드립니다. 나는 Bas Brekelmans를 당신이 썼을 때 혼란 스러웠습니다. - Kirill Shlenskiy

관련된 질문

최근 질문