기다리지 않고 C #에서 비동기 메서드를 안전하게 호출하는 방법
나는이 async
데이터를 반환 방법 :
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
일부 데이터를 반환하는 다른 메서드에서 이것을 호출합니다.
public string GetStringData()
{
MyAsyncMethod(); // this generates a warning and swallows exceptions
return "hello world";
}
MyAsyncMethod()
기다리지 않고 호출 하면 Visual Studio에서 " 이 호출 을 기다리지 않기 때문에 호출이 완료되기 전에 현재 메서드가 계속 실행됩니다 "경고가 발생합니다. 해당 경고 페이지에는 다음이 표시됩니다.
비동기 호출이 완료되기를 기다리지 않고 호출 된 메소드가 예외를 발생시키지 않는 경우에만 경고를 억제하는 것을 고려해야합니다 .
전화가 끝날 때까지 기다리지 않겠다고 확신합니다. 시간이 필요 없거나 시간이 없습니다. 그러나 전화로 예외 가 발생할 수 있습니다 .
나는이 문제에 몇 번 걸려 넘어졌으며 일반적인 해결책이 있어야하는 일반적인 문제라고 확신합니다.
결과를 기다리지 않고 어떻게 비동기 메소드를 안전하게 호출합니까?
최신 정보:
결과를 기다리겠다고 제안하는 사람들에게 이것은 웹 서비스 (ASP.NET 웹 API)의 웹 요청에 응답하는 코드입니다. UI 컨텍스트에서 대기하면 UI 스레드가 사용 가능한 상태로 유지되지만 웹 요청 호출에서 대기하면 요청에 응답하기 전에 작업이 완료 될 때까지 대기하므로 아무런 이유없이 응답 시간이 늘어납니다.
"비동기 적으로"예외를 얻으려면 다음을 수행하십시오.
MyAsyncMethod().
ContinueWith(t => Console.WriteLine(t.Exception),
TaskContinuationOptions.OnlyOnFaulted);
이렇게하면 "메인"스레드 이외의 스레드에서 예외를 처리 할 수 있습니다. 즉, 호출 MyAsyncMethod()
하는 스레드에서 호출을 "대기"할 필요가 없습니다 MyAsyncMethod
. 그러나 여전히 예외로 무언가를 할 수는 있지만 예외가 발생하는 경우에만 가능합니다.
최신 정보:
기술적으로 다음과 비슷한 작업을 수행 할 수 있습니다 await
.
try
{
await MyAsyncMethod().ConfigureAwait(false);
}
catch (Exception ex)
{
Trace.WriteLine(ex);
}
... 특별히 사용하는 데 필요한 경우에 유용 할 것이다 try
/ catch
(또는 using
)하지만 난 찾을 ContinueWith
당신이 알고 있기 때문에 좀 더 명시 적으로 ConfigureAwait(false)
수단을.
먼저 만드는 것이 좋습니다 방법과이 에서 반환 된 작업 .GetStringData
async
await
MyAsyncMethod
예외를 처리 할 필요가 MyAsyncMethod
없거나 완료 시점을 알 필요가없는 경우 다음을 수행 할 수 있습니다.
public string GetStringData()
{
var _ = MyAsyncMethod();
return "hello world";
}
BTW, 이것은 "일반적인 문제"가 아닙니다. 그것은 몇 가지 코드를 실행하고 완료 여부를 상관하지 싶어 매우 희귀 하고 성공적으로 완료 여부를 상관하지.
최신 정보:
ASP.NET을 사용하고 있고 일찍 돌아가고 싶기 때문에 주제에 대한 내 블로그 게시물이 유용하다는 것을 알 수 있습니다. 그러나 ASP.NET은이를 위해 설계된 것이 아니며 응답이 반환 된 후에 코드가 실행된다는 보장 이 없습니다 . ASP.NET은 실행되도록 최선을 다하지만 보장 할 수는 없습니다.
따라서 이것은 이벤트를 로그로 던져서 여기저기서 몇 가지를 잃어도 실제로 중요 하지 않은 간단한 방법에 대한 훌륭한 솔루션입니다 . 모든 종류의 비즈니스 크리티컬 운영에 적합한 솔루션은 아닙니다. 이러한 상황에서는 작업 (예 : Azure Queues, MSMQ)을 저장하고 별도의 백그라운드 프로세스 (예 : Azure Worker Role, Win32 Service)를 저장하는 지속적인 방법으로보다 복잡한 아키텍처를 채택 해야 합니다.
Peter Ritchie의 대답은 내가 원했던 것이 었으며 ASP.NET에서 일찍 돌아 오는 것에 대한 Stephen Cleary의 기사 는 매우 도움이되었습니다.
그러나보다 일반적인 문제 (ASP.NET 컨텍스트에만 해당되지 않음) 다음 콘솔 응용 프로그램은 다음을 사용하여 Peter의 답변 사용 및 동작을 보여줍니다. Task.ContinueWith(...)
static void Main(string[] args)
{
try
{
// output "hello world" as method returns early
Console.WriteLine(GetStringData());
}
catch
{
// Exception is NOT caught here
}
Console.ReadLine();
}
public static string GetStringData()
{
MyAsyncMethod().ContinueWith(OnMyAsyncMethodFailed, TaskContinuationOptions.OnlyOnFaulted);
return "hello world";
}
public static async Task MyAsyncMethod()
{
await Task.Run(() => { throw new Exception("thrown on background thread"); });
}
public static void OnMyAsyncMethodFailed(Task task)
{
Exception ex = task.Exception;
// Deal with exceptions here however you want
}
GetStringData()
초기 기다리고없이 반환 MyAsyncMethod()
에 던져 예외 MyAsyncMethod()
로 처리되어 OnMyAsyncMethodFailed(Task task)
및 하지 에서 try
/ catch
주변GetStringData()
이 솔루션으로 끝납니다.
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
public string GetStringData()
{
// Run async, no warning, exception are catched
RunAsync(MyAsyncMethod());
return "hello world";
}
private void RunAsync(Task task)
{
task.ContinueWith(t =>
{
ILog log = ServiceLocator.Current.GetInstance<ILog>();
log.Error("Unexpected Error", t.Exception);
}, TaskContinuationOptions.OnlyOnFaulted);
}
이것을 fire and forget이라고하며 확장 기능 이 있습니다.
작업을 수행하고 아무 작업도 수행하지 않습니다. 비동기 메소드 내에서 비동기 메소드에 대한 실행 및 호출에 유용합니다.
nuget 패키지를 설치 하십시오 .
사용하다:
MyAsyncMethod().Forget();
질문이 생겼을 것 같습니다. 왜 이렇게해야합니까? async
C # 5.0 의 이유 는 결과를 기다릴 수 있기 때문입니다. 이 메소드는 실제로는 비동기 적이 지 않지만 현재 스레드를 너무 많이 방해하지 않도록 한 번에 간단히 호출됩니다.
아마도 스레드를 시작하고 그대로 두는 것이 좋습니다.
해결책은 sincronization 컨텍스트없이 HttpClient를 다른 실행 작업으로 시작하는 것입니다.
var submit = httpClient.PostAsync(uri, new StringContent(body, Encoding.UTF8,"application/json"));
var t = Task.Run(() => submit.ConfigureAwait(false));
await t.ConfigureAwait(false);
메시지 루프가있는 기술 (ASP가 그 중 하나인지 확실하지 않은 기술)에서는 작업이 끝날 때까지 루프를 차단하고 메시지를 처리하고 ContinueWith를 사용하여 코드를 차단 해제 할 수 있습니다.
public void WaitForTask(Task task)
{
DispatcherFrame frame = new DispatcherFrame();
task.ContinueWith(t => frame.Continue = false));
Dispatcher.PushFrame(frame);
}
이 방법은 ShowDialog를 차단하고 UI를 계속 반응시키는 것과 유사합니다.
'Programing' 카테고리의 다른 글
Maven 부모 pom 대 모듈 pom (0) | 2020.03.24 |
---|---|
PHP에서 사용자의 올바른 IP 주소를 검색하는 가장 정확한 방법은 무엇입니까? (0) | 2020.03.24 |
Visual Studio에서 문서 간 이동을위한 Ctrl + Tab 동작 변경 (0) | 2020.03.24 |
stopPropagation vs. stopImmediatePropagation (0) | 2020.03.24 |
NodeJS / Express :“app.use”란 무엇입니까? (0) | 2020.03.24 |