지난 며칠 동안 .net 4.5 및 c # 5의 새로운 기능을 테스트했습니다.
새로운 비동기 / 대기 기능이 마음에 듭니다. 이전 에는 반응 형 UI로 백그라운드에서 더 긴 프로세스를 처리하기 위해 BackgroundWorker 를 사용했습니다 .
내 질문은 :이 멋진 새로운 기능을 가지고 나면 언제 async / await를 사용해야하고 BackgroundWorker를 사용해야 합니까? 둘 다에 대한 일반적인 시나리오는 무엇입니까?
지난 며칠 동안 .net 4.5 및 c # 5의 새로운 기능을 테스트했습니다.
새로운 비동기 / 대기 기능이 마음에 듭니다. 이전 에는 반응 형 UI로 백그라운드에서 더 긴 프로세스를 처리하기 위해 BackgroundWorker 를 사용했습니다 .
내 질문은 :이 멋진 새로운 기능을 가지고 나면 언제 async / await를 사용해야하고 BackgroundWorker를 사용해야 합니까? 둘 다에 대한 일반적인 시나리오는 무엇입니까?
답변:
async / await는와 같은 구문을 대체하도록 설계되었습니다 BackgroundWorker
. 원하는 경우 확실히 사용할 수 있지만 다른 TPL 도구와 함께 async / await를 사용하여 외부에있는 모든 것을 처리 할 수 있어야합니다.
두 가지 모두 작동하기 때문에 언제 사용하는지에 대한 개인적인 취향에 달려 있습니다. 대한 빠른 무엇 당신 ? 무엇을 위해 쉽게 당신이 이해하기?
이것은 많은 사람들에게 TL; DR 일 가능성이 있지만, 비교 await
하는 BackgroundWorker
것은 사과와 오렌지를 비교하는 것과 같다고 생각합니다.
BackgroundWorker
스레드 풀 스레드에서 백그라운드에서 수행하려는 단일 작업을 모델링하기위한 것입니다. async
/ await
는 비동기 작업을 비동기 적으로 기다리는 구문입니다. 이러한 작업 또는 스레드 풀 스레드를 사용하거나 사용하지 않을 수 있습니다 다른 스레드를 . 그래서 그들은 사과와 오렌지입니다.
예를 들어 다음과 같은 작업을 수행 할 수 있습니다 await
.
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
그러나 백그라운드 작업자에서는 .NET 4.0에서 이전과 같이 다음과 같은 작업을 수행하지 않을 것입니다 await
.
webReq.BeginGetResponse(ar =>
{
WebResponse response = webReq.EndGetResponse(ar);
Stream responseStream = response.GetResponseStream();
responseStream.BeginRead(buffer, 0, buffer.Length, ar2 =>
{
int bytesRead = responseStream.EndRead(ar2);
responseStream.Dispose();
((IDisposable) response).Dispose();
}, null);
}, null);
두 구문 사이에서 처리의 분리와 / using
없이 사용 하지 않는 방법에 주목하십시오 .async
await
그러나으로 그런 일을하지 않을 것입니다 BackgroundWorker
. BackgroundWorker
UI 응답성에 영향을 미치지 않으려는 장기 실행 작업을 모델링하는 데 주로 사용됩니다. 예를 들면 다음과 같습니다.
worker.DoWork += (sender, e) =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
};
worker.RunWorkerCompleted += (sender, eventArgs) =>
{
// TODO: do something on the UI thread, like
// update status or display "result"
};
worker.RunWorkerAsync();
async / await와 함께 사용할 수있는 것은 아무것도 없으며 BackgroundWorker
스레드를 생성하는 것입니다.
이제 대신 TPL을 사용할 수 있습니다.
var synchronizationContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
}).ContinueWith(t=>
{
// TODO: do something on the UI thread, like
// update status or display "result"
}, synchronizationContext);
어떤 경우에는 TaskScheduler
당신을 위해 스레드를 생성하고 (기본값이라고 가정 TaskScheduler
) 사용할 수 있습니다await
다음과 같이 :
await Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
});
// TODO: do something on the UI thread, like
// update status or display "result"
내 의견으로는, 주요한 비교는 당신이 진행 상황을보고하고 있는지 아닌지입니다. 예를 들어BackgroundWorker like
이것을 :
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (sender, eventArgs) =>
{
// TODO: something with progress, like update progress bar
};
worker.DoWork += (sender, e) =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
{
if ((sw.Elapsed.TotalMilliseconds%100) == 0)
((BackgroundWorker)sender).ReportProgress((int) (1000 / sw.ElapsedMilliseconds));
++i;
}
};
worker.RunWorkerCompleted += (sender, eventArgs) =>
{
// do something on the UI thread, like
// update status or display "result"
};
worker.RunWorkerAsync();
당신이 할 수없는 뭔가를 -하지만,이 중 일부를 처리하지 않을 당신은 드래그 앤 드롭 형태의 디자인 화면에 배경 작업자 구성 요소를 것 때문에 async
/ await
과 Task
'즉, 당신이 원 ... t 객체를 수동으로 생성하고 속성을 설정하고 이벤트 핸들러를 설정하십시오. 당신은 단지의 몸을 기입 것 DoWork
, RunWorkerCompleted
및 ProgressChanged
이벤트 핸들러.
이를 "비동기 / 대기"로 변환 한 경우 다음과 같은 작업을 수행합니다.
IProgress<int> progress = new Progress<int>();
progress.ProgressChanged += ( s, e ) =>
{
// TODO: do something with e.ProgressPercentage
// like update progress bar
};
await Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
{
if ((sw.Elapsed.TotalMilliseconds%100) == 0)
{
progress.Report((int) (1000 / sw.ElapsedMilliseconds))
}
++i;
}
});
// TODO: do something on the UI thread, like
// update status or display "result"
구성 요소를 Designer 화면으로 끌어 올 수 없으면 "더 나은"구성 요소를 결정하는 것은 독자의 몫입니다. 그러나, 나에게, 와 같은 내장 메소드를 기다릴 수 있는지 아닌지 await
와 의 비교입니다.BackgroundWorker
Stream.ReadAsync
입니다. 예를 들어 BackgroundWorker
의도 한대로 사용 하는 경우 사용 으로 변환하기 어려울 수 있습니다 await
.
다른 생각 : http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html
var t1 = webReq.GetResponseAsync(); var t2 = webReq2.GetResponseAsync(); await t1; await t2;
. 두 개의 병렬 작업을 기다리는 것입니다. Await는 비동기 적이지만 순차적 작업 인 IMO에 훨씬 좋습니다.
await Task.WhenAny(t1, t2)
두 작업 중 하나가 먼저 완료되었을 때 무언가를 수행 하는 데 사용할 수 있습니다. 다른 작업도 완료하도록 루프를 원할 것입니다. 일반적으로 특정 작업이 완료되는 시기를 알고 싶어서 순차적을 작성하게됩니다 await
.
이것은 좋은 소개입니다 : http://msdn.microsoft.com/en-us/library/hh191443.aspx 스레드 섹션은 당신이 찾고있는 것입니다.
비동기 메서드는 비 차단 작업입니다. 비동기 메서드의 대기 식은 대기중인 작업이 실행되는 동안 현재 스레드를 차단하지 않습니다. 대신, 표현식은 나머지 메소드를 연속으로 등록하고 비동기 메소드의 호출자에게 제어를 리턴합니다.
async 및 await 키워드는 추가 스레드를 생성하지 않습니다. 비동기 메서드는 자체 스레드에서 실행되지 않으므로 비동기 메서드에는 멀티 스레딩이 필요하지 않습니다. 메소드는 현재 동기화 컨텍스트에서 실행되며 메소드가 활성화 된 경우에만 스레드에서 시간을 사용합니다. Task.Run을 사용하여 CPU 바운드 작업을 백그라운드 스레드로 이동할 수 있지만 백그라운드 스레드는 결과를 사용할 수있을 때까지 기다리는 프로세스에는 도움이되지 않습니다.
비동기 프로그래밍에 대한 비동기 기반 접근 방식은 거의 모든 경우에 기존 접근 방식보다 선호됩니다. 특히,이 방법은 코드가 더 간단하고 경쟁 조건을 막을 필요가 없기 때문에 IO 바운드 작업의 경우 BackgroundWorker보다 좋습니다. 비동기 프로그래밍은 Task.Run이 스레드 풀로 전송하는 작업과 코드 실행에 대한 조정 세부 사항을 분리하기 때문에 Task.Run과 함께 CPU에 바인딩 된 작업의 경우 BackgroundWorker보다 비동기 프로그래밍이 더 좋습니다.
BackgroundWorker 는 .NET 4.5에서 사용되지 않는 것으로 명시 적으로 표시됩니다.
MSDN 기사 "Async 및 Await를 사용한 비동기 프로그래밍 (C # 및 Visual Basic)" 은 다음과 같이 알려줍니다.
비동기 프로그래밍에 대한 비동기 기반 접근 방식은 거의 모든 경우에 기존 접근 방식보다 선호됩니다 . 특히,이 방법은 코드가 더 간단하고 경쟁 조건을 막을 필요가 없기 때문에 IO 바운드 작업의 경우 BackgroundWorker 보다 낫습니다 . 비동기 프로그래밍은 Task.Run 이 스레드 풀로 전송 하는 작업과 코드 실행에 대한 조정 세부 사항을 분리하기 때문에 Task.Run과 함께 CPU 기반 작업의 경우 비동기 프로그래밍이 BackgroundWorker 보다 낫습니다.
최신 정보
이 질문은 별도의 게시물로 작성해야합니다.
Wikipedia에는 경주 조건에 대한 좋은 설명이 있습니다. 그중 필요한 부분은 멀티 스레딩이며 동일한 MSDN 기사 Async and Await를 사용한 비동기 프로그래밍 (C # 및 Visual Basic)입니다 .
비동기 메서드는 비 차단 작업입니다. 비동기 메서드의 대기 식은 대기중인 작업이 실행되는 동안 현재 스레드를 차단하지 않습니다. 대신, 표현식은 나머지 메소드를 연속으로 등록하고 비동기 메소드의 호출자에게 제어를 리턴합니다.
async 및 await 키워드는 추가 스레드를 생성하지 않습니다. 비동기 메서드는 자체 스레드에서 실행되지 않으므로 비동기 메서드에는 멀티 스레딩이 필요하지 않습니다. 메소드는 현재 동기화 컨텍스트에서 실행되며 메소드가 활성화 된 경우에만 스레드에서 시간을 사용합니다. Task.Run을 사용하여 CPU 바운드 작업을 백그라운드 스레드로 이동할 수 있지만 백그라운드 스레드는 결과를 사용할 수있을 때까지 기다리는 프로세스에는 도움이되지 않습니다.
비동기 프로그래밍에 대한 비동기 기반 접근 방식은 거의 모든 경우에 기존 접근 방식보다 선호됩니다. 특히,이 방법은 코드가 더 간단하고 경쟁 조건을 막을 필요가 없기 때문에 IO 바운드 작업의 경우 BackgroundWorker보다 좋습니다. 비동기 프로그래밍은 Task.Run이 스레드 풀로 전송하는 작업과 코드 실행에 대한 조정 세부 사항을 분리하기 때문에 Task.Run과 함께 CPU 기반 작업의 경우 비동기 프로그래밍이 BackgroundWorker보다 낫습니다.
즉, "async 및 await 키워드는 추가 스레드를 만들지 않습니다".
1 년 전에이 기사를 공부할 때 내 시도를 기억할 수있는 한, 같은 기사의 코드 샘플을 실행하여 재생 한 경우 비동기 버전의 상황에 부딪 칠 수 있습니다 (변환을 시도 할 수 있음) 스스로에게) 무한정 차단!
또한 구체적인 예를 보려면이 사이트를 검색하십시오. 다음은 몇 가지 예입니다.