복잡한 계산 알고리즘을 구축했습니다. 완료하는 데는 꽤 시간이 걸리고 응용 프로그램이 응답 성을 유지하는지 확인하려고합니다. 너 뭐하니?
대답은 C입니다.하지만 누군가 A)가 틀렸다고 설명 할 수 있습니까? 질문은 복잡한 알고리즘이 CPU에 묶여 있다고 말하지 않기 때문입니다. 만약 CPU가 바운드라면, 우리는 Tasks를 사용해야 할 것입니다. (나는 그 태스크가 완료 될 때까지 현재의 쓰레드가 일시 중지되도록 도와 주지만, 너무 잘 이해하지 못합니다.) 또한 async / await를 사용할시기를 결정하고 작업을 사용하는 방법을 설명하십시오.
너 뭐하니?
A. async / await를 사용하십시오.
B. 코드를 동 기적으로 실행하십시오.
C. Task.Run을 사용하십시오.
D. BackgroundWorker를 사용하십시오.
그만큼async/await
C #5.0의 기능은 비동기 코드를 동기식 코드를 작성하는 것처럼 "쉽게"만들 수 있도록 구현되었습니다. WinAPI를 살펴보면 거의 모든 비동기 끝점이 완전 비동기 API를 노출한다는 것을 알 수 있습니다. 즉,실이 없다.. 더 자세히 살펴보면 같은 엔드 포인트가I / O 경계작업.
귀하의 알고리즘을 가정하면CPU 바운드, 여러 프로세서에서 효과적으로 계산할 수있는 방식으로 작성됩니다 (예 : 알고리즘에 동기화가 필요한 공유 상태가 없음).작업 병렬 라이브러리.NET 4.0에 도입되었습니다. TPL은 다중 프로세서 환경에서 작업을 균등하게 오프로드하려고 시도하는 ThreadPool에 대한 추상화를 제공합니다.
그만큼await
키워드는기다리고있는object : 객체가GetAwaiter
방법. 당신은await
당신이 기다릴 수있는 것을 사용하고있을 때 그 일이 그 일을 끝내면 다시 시작하기를 원할 때. 에이Task
기다릴 수있는 패턴을 구현하고 장래에 완료 될 작업 단위를 설명하는 데 사용됩니다. 당신이 사용할 수있는Task.Run
과await
, 작업 스레드에서 작업 단위를 오프로드하려는 경우그 작업이 끝날 때까지 호출 메소드에 제어권을 되 돌린다..
여러 프로세서에서 CPU 바운드 작업을 디스패치하는 또 다른 방법은Parallel
노출하는 클래스Parallel.For
과Parallel.ForEach
.
참고로,BackgroundWorker
배경 스레드에서 작업을 오프로드하는 데 사용할 수도 있습니다. 그것은추천 된.NET 4.0이 발표 된 이래로 TPL을 사용했다.
결론을 맺으려면 작업 병렬 라이브러리를 사용하여 작업을 백그라운드 스레드로 오프로드하는 것이 좋습니다. 귀하는 이들을 함께 사용할 수 있습니다.Parallel
라이브러리를 사용하여 알고리즘의 병렬 처리를 극대화하십시오. 그렇게 한 후에,코드 테스트하기여러 스레드를 사용하는 오버 헤드가 알 고를 동 기적으로 실행하는 데 걸리는 시간보다 중요하지 않은지 확인하십시오.
편집하다
Stephan이 의견에서 언급했듯이,Parallel.ForEach
과Task.Run
백그라운드 스레드 내에서 병렬 루프를 오프로드하는 방법 :
var task = Task.Run(() => Parallel.ForEach(.. //Loop here));
await Task.Run(() => Parallel.ForEach(...))
UI가 비동기로 처리하는 백그라운드 스레드에 대해 병렬 작업을 수행합니다. - Stephen Cleary
나는 "계산"이 다른 정보가 없을 때 CPU 바운드 알고리즘을 의미한다고 가정합니다. 알고리즘이 IO 바인딩 인 경우 비동기 / 대기가 허용 될뿐만 아니라 정답입니다.
Task.Run
, 전달 된 델리게이트는 UI 스레드가 아닌 다른 스레드에서 실행될 가능성이 높습니다.귀하의 UI는 반응 형으로 유지 될 것입니다.어떤 경우 에든 작업 완료를 막지 못하는 경우Wait()
또는Result
. 작업 완료를 처리하고 호출 한 스레드와 통신하는 방법Task.Run
그러나 우선, 당신에게 달려 있습니다 : 당신은await
, 또는 적절한 작업 연속 작업을 사용할 수 있습니다TaskScheduler
, 또는 원래 SynchronizationContext를 명시 적으로 캡처하여 대리자 내에서 다시 게시 할 수 있습니다. - Kirill ShlenskiyDispatcher.Invoke
또는Control.Invoke
, 또는 자신 만의 AsyncEnumerator를 롤 할 수 있습니다 (blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx). 요점은 약 백만 가지 방법이 있다는 것입니다.async/await
모든 사람의 마음에 가장 먼저 떠오르는 것이라 할지라도, 그 중 하나가 될 수 있습니다. - Kirill Shlenskiy
질문은 당신이 동기식으로 프로그램 된 알고리즘을 가지고 있다고 가정합니다. 질문은 이것이 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 둘 다가 될 것이다. 어쨌든 그 질문은 너무 확고하여 어떤 확고한 결론을 도출하지 못한다.
xxxAsync
CPU 바운드 작업에 대한 래퍼는 디자인이 좋지 않습니다. 호출자가 줄 바꿈 할 수 없다는 점CalculateStuff
...에서Task.Run
필요하다면. 또한 다음을 고려하십시오.CalculateStuffAsync().Wait()
. 없이ConfigureAwait(false)
교착 상태 버그가 발생했습니다. 교착 상태 버그는async
방법, 거의 제로 이익을 위해. - Kirill ShlenskiySynchronizationContext
(즉, Windows Forms / WPF) 무엇이 발생하는지 확인하십시오. 이것은 귀하의await
원래 상태로 전환해야합니다.SynchronizationContext
비동기 작업의 결과가 반환 될 수 있습니다. 스레드를 통해 차단하는 경우Task.Wait
쓰레드가 작업을 기다리면서 바쁠 것이기 때문에 결코 바뀌지 않을 것입니다. 장군. 테이크 아웃async/await
작업을 직접 반환하면 해결됩니다. - Kirill ShlenskiyConfigureAwait(false)
명백하게) - Kirill Shlenskiy