async / await-언제 작업 대 무효를 반환합니까?
어떤 시나리오에서 사용하고 싶습니까?
public async Task AsyncMethod(int num)
대신에
public async void AsyncMethod(int num)
내가 생각할 수있는 유일한 시나리오는 진행 상황을 추적 할 수있는 작업이 필요한 경우입니다.
또한 다음 방법에서 async 및 await 키워드가 필요하지 않습니까?
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
1) 일반적으로 a를 반환하려고합니다 Task
. 이벤트의 경우 리턴 유형 이 필요한 경우는 예외 void
입니다. 발신자 await
에게 작업 을 허용하지 않을 이유가 없다면 왜 허용하지 않습니까?
2) async
리턴 void
하는 메소드 는 다른 측면에서 특별합니다. 메소드는 최상위 비동기 조작 을 나타내며 태스크가 예외를 리턴 할 때 적용되는 추가 규칙이 있습니다. 차이점을 보여주는 가장 쉬운 방법은 예제를 사용하는 것입니다.
static async void f()
{
await h();
}
static async Task g()
{
await h();
}
static async Task h()
{
throw new NotImplementedException();
}
private void button1_Click(object sender, EventArgs e)
{
f();
}
private void button2_Click(object sender, EventArgs e)
{
g();
}
private void button3_Click(object sender, EventArgs e)
{
GC.Collect();
}
f
예외는 항상 "관측"됩니다. 최상위 비동기 메소드를 남기는 예외는 처리되지 않은 다른 예외처럼 간단하게 처리됩니다. g
의 예외는 관찰되지 않습니다. 가비지 수집기가 작업을 정리하면 해당 작업에서 예외가 발생하여 예외를 처리 한 사람이 없음을 알 수 있습니다. 이 경우 TaskScheduler.UnobservedTaskException
핸들러가 실행됩니다. 이런 일이 일어나지 않도록해야합니다. 예를 사용하려면
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
예, 사용 async
하고 await
여기에, 그들은 예외가 발생하는 경우 반드시 당신의 방법은 여전히 제대로 작동합니다.
자세한 정보는 http://msdn.microsoft.com/en-us/magazine/jj991977.aspx를 참조하십시오.
나는 약이 매우 유용한 기사를 통해 온 async
과 void
제롬 라반에 의해 작성 : https://jaylee.org/archive/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void .html
결론 async+void
은 시스템을 중단시킬 수 있으며 일반적으로 UI 측 이벤트 핸들러에서만 사용해야한다는 것입니다.
그 이유는 AsyncVoidMethodBuilder에서 사용하는 동기화 컨텍스트이므로이 예제에서는 없습니다. 앰비언트 동기화 컨텍스트가없는 경우 비동기 void 메소드 본문에서 처리되지 않은 예외는 ThreadPool에서 다시 발생합니다. 처리되지 않은 예외가 발생할 수있는 다른 논리적 장소는 없지만, 불행하게도 ThreadPool의 처리되지 않은 예외는 .NET 2.0 이후 프로세스를 효과적으로 종료하기 때문에 프로세스가 종료되는 것입니다. AppDomain.UnhandledException 이벤트를 사용하여 처리되지 않은 모든 예외를 가로 챌 수 있지만이 이벤트에서 프로세스를 복구 할 수있는 방법은 없습니다.
UI 이벤트 핸들러를 작성할 때 예외가 비동기가 아닌 메소드에서 발견 된 것과 동일한 방식으로 처리되므로 비동기 void 메소드는 아무 문제가 없습니다. 그들은 디스패처에 던져집니다. 이러한 예외를 복구 할 가능성이 있으며 대부분의 경우 올바른 것 이상입니다. 그러나 UI 이벤트 핸들러 외부에서 비동기 void 메소드는 사용하기에 위험하며 찾기가 쉽지 않을 수 있습니다.
나는이 진술에서 분명한 아이디어를 얻었다.
- 비동기 void 메소드에는 서로 다른 오류 처리 의미가 있습니다. 비동기 작업 또는 비동기 작업 메서드에서 예외가 발생하면 해당 예외가 캡처되어 Task 개체에 배치됩니다. 비동기 void 메소드에는 Task 객체가 없으므로 비동기 void 메소드에서 발생하는 예외는 SynchronizationContext (SynchronizationContext는 "where"코드가 실행될 수있는 위치를 나타냄)에서 직접 발생합니다. 시작
비동기 공허 메서드의 예외는 캐치로 잡을 수 없습니다
private async void ThrowExceptionAsync()
{
throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
try
{
ThrowExceptionAsync();
}
catch (Exception)
{
// The exception is never caught here!
throw;
}
}
이러한 예외는 AppDomain.UnhandledException 또는 GUI / ASP.NET 응용 프로그램에 대한 유사한 catch-all 이벤트를 사용하여 관찰 할 수 있지만 정기적 인 예외 처리를 위해 해당 이벤트를 사용하는 것은 유지 보수를위한 레시피입니다 (응용 프로그램이 충돌 함).
비동기 void 메소드에는 서로 다른 구성 의미가 있습니다. Task 또는 Task를 반환하는 비동기 메서드는 await, Task.WhenAny, Task.WhenAll 등을 사용하여 쉽게 구성 할 수 있습니다. void를 반환하는 비동기 메서드는 호출 코드가 완료되었음을 알리는 쉬운 방법을 제공하지 않습니다. 여러 가지 비동기 void 메소드를 시작하는 것은 쉽지만 완료 시점을 결정하는 것은 쉽지 않습니다. 비동기 void 메소드는 시작 및 완료시 SynchronizationContext에 알리지 만 사용자 정의 SynchronizationContext는 일반 애플리케이션 코드에 대한 복잡한 솔루션입니다.
비동기 이벤트 핸들러를 사용하는 경우 비동기 이벤트 핸들러가 동작하는 방식과 유사한 SynchronizationContext에서 직접 예외를 발생시키기 때문에 비동기 무효화 메소드가 유용합니다.
자세한 내용은이 링크를 확인하십시오 https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
async void 호출의 문제점은 작업을 다시 얻지 못하고 기능 작업이 완료된 시점을 알 방법이 없다는 것입니다 ( https://blogs.msdn.microsoft.com/oldnewthing/20170720-00/ ? p = 96655 )
비동기 함수를 호출하는 세 가지 방법은 다음과 같습니다.
async Task<T> SomethingAsync() { ... return t; }
async Task SomethingAsync() { ... }
async void SomethingAsync() { ... }
모든 경우에 함수는 일련의 작업으로 변환됩니다. 차이점은 함수가 반환하는 것입니다.
첫 번째 경우 함수는 결국 t를 생성하는 작업을 반환합니다.
두 번째 경우, 함수는 제품이없는 태스크를 리턴하지만 완료 될 때까지 알기 위해 계속 기다릴 수 있습니다.
세 번째 사례는 불쾌한 사례입니다. 세 번째 경우는 두 번째 경우와 비슷하지만 작업을 다시받지 못합니다. 함수의 작업이 완료된 시점을 알 방법이 없습니다.
비동기 무효 사례는 "화재와 잊어 버리기"입니다. 작업 체인을 시작하지만 완료 시점에 대해서는 신경 쓰지 않습니다. 함수가 반환되면 처음으로 기다리는 모든 것이 실행되었다는 것입니다. 첫 번째 대기 이후의 모든 항목은 나중에 액세스 할 수없는 지정되지 않은 지점에서 실행됩니다.
async void
예외를 잡는 데주의를 기울이는 한 백그라운드 작업을 시작 하는 데 사용할 수 있다고 생각합니다 . 생각?
class Program {
static bool isFinished = false;
static void Main(string[] args) {
// Kick off the background operation and don't care about when it completes
BackgroundWork();
Console.WriteLine("Press enter when you're ready to stop the background operation.");
Console.ReadLine();
isFinished = true;
}
// Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
static async void BackgroundWork() {
// It's important to catch exceptions so we don't crash the appliation.
try {
// This operation will end after ten interations or when the app closes. Whichever happens first.
for (var count = 1; count <= 10 && !isFinished; count++) {
await Task.Delay(1000);
Console.WriteLine($"{count} seconds of work elapsed.");
}
Console.WriteLine("Background operation came to an end.");
} catch (Exception x) {
Console.WriteLine("Caught exception:");
Console.WriteLine(x.ToString());
}
}
}
내 대답은 간단합니다. void 메소드를 기다릴 수 없습니다.
Error CS4008 Cannot await 'void' TestAsync e:\test\TestAsync\TestAsyncProgram.cs
따라서 메소드가 비동기 인 경우 비동기 이점을 잃을 수 있기 때문에 대기하는 것이 좋습니다.
참고 URL : https://stackoverflow.com/questions/12144077/async-await-when-to-return-a-task-vs-void
도와주세요.
'development' 카테고리의 다른 글
LDAP 검색에서 CN, OU, DC 란 무엇입니까? (0) | 2020.02.17 |
---|---|
Android 기기에서 apk 파일을 어떻게 얻습니까? (0) | 2020.02.17 |
GitHub에 대한 이슈 코멘트에서 커밋을 어떻게 참조 할 수 있습니까? (0) | 2020.02.17 |
printf에서 double에 대한 올바른 형식 지정자 (0) | 2020.02.17 |
Docker에서 "노출"과 "게시"의 차이점은 무엇입니까? (0) | 2020.02.17 |