비동기 코드에서 비동기 메서드를 호출합니다.
에 내장된 API 서페이스가 있는 라이브러리를 업데이트하는 중입니다.NET 3.5. 그 결과 모든 방법이 동기화됩니다.API를 변경할 수 없습니다(즉, 반환 값을 태스크로 변환). 모든 발신자를 변경해야 합니다.따라서 동기식으로 비동기 메서드를 호출하는 최선의 방법이 남아 있습니다.이것은 ASP의 컨텍스트입니다.NET 4, ASPNET Core 및.NET/.NET 코어 콘솔애플리케이션
확실히 알 수 없었던 것 같습니다.비동기 인식이 되지 않는 기존 코드가 있어 시스템 등의 새로운 라이브러리를 사용하고 싶다고 생각하고 있습니다.비동기 메서드만 지원하는 Net.Http 및 AWS SDK.따라서 갭을 메우고 동기적으로 호출할 수 있지만 다른 곳에서 비동기 메서드를 호출할 수 있는 코드를 가질 필요가 있습니다.
제가 많이 읽어봤는데 여러 번 물어보고 대답한 적이 있어요.
동기적으로 비동기 조작을 기다리고 있습니다.Wait()는 왜 여기서 프로그램을 프리즈합니까?
C#의 동기 메서드에서 비동기 메서드를 호출하려면 어떻게 해야 합니까?
문제는 대부분의 답이 다르다는 거예요!지금까지 본 가장 일반적인 접근법은 을 사용하는 것입니다.결과이지만 교착 상태가 될 수 있습니다.다음을 모두 시도해 봤지만, 어떤 방법이 교착 상태를 방지하고, 좋은 성능을 발휘하며, 런타임과 잘 어울리는지 잘 모르겠습니다(태스크 스케줄러, 태스크 작성 옵션 등).확실한 답이 있나요?가장 좋은 접근법은 무엇입니까?
private static T taskSyncRunner<T>(Func<Task<T>> task)
{
T result;
// approach 1
result = Task.Run(async () => await task()).ConfigureAwait(false).GetAwaiter().GetResult();
// approach 2
result = Task.Run(task).ConfigureAwait(false).GetAwaiter().GetResult();
// approach 3
result = task().ConfigureAwait(false).GetAwaiter().GetResult();
// approach 4
result = Task.Run(task).Result;
// approach 5
result = Task.Run(task).GetAwaiter().GetResult();
// approach 6
var t = task();
t.RunSynchronously();
result = t.Result;
// approach 7
var t1 = task();
Task.WaitAll(t1);
result = t1.Result;
// approach 8?
return result;
}
따라서 동기식으로 비동기 메서드를 호출하는 최선의 방법이 남아 있습니다.
첫째, 이것은 할 수 있는 일이다.Stack Overflow에서 이것을 구체적인 사건과는 무관한 포괄적인 진술로 지적하는 것이 일반적이기 때문에 이 말을 하는 것이다.
정확성을 위해 항상 비동기일 필요는 없습니다.비동기적인 것을 차단하여 동기화하는 것은 퍼포먼스 비용이 중요하거나 전혀 관계가 없을 수 있습니다.구체적인 케이스에 따라 다릅니다.
데드록은 동일한 단일 스레드 동기 컨텍스트에 동시에 들어가려고 하는2개의 스레드에서 발생합니다.이를 회피하는 모든 기술은 블로킹으로 인한 교착 상태를 확실하게 회피합니다.
코드 스니펫에서 모든 콜은.ConfigureAwait(false)
반환값이 대기되지 않기 때문에 의미가 없습니다. ConfigureAwait
대기 시 요청된 동작을 나타내는 구조체를 반환합니다.그 구조물이 그냥 떨어지면 아무 것도 할 수 없다.
RunSynchronously
모든 작업을 이 방법으로 처리할 수 없기 때문에 를 사용할 수 없습니다.이 방법은 CPU 기반 작업을 위한 것으로, 특정 상황에서는 작동하지 않을 수 있습니다.
.GetAwaiter().GetResult()
와는 다르다Result/Wait()
그 점이 가장 닮아 있다는 점에서는await
예외 전파 동작.당신은 그것을 원하는지 아닌지를 결정해야 합니다. (그러니까 그 행동이 무엇인지 조사하세요.여기서 반복할 필요는 없습니다.)태스크에 예외가1개 포함되어 있는 경우await
에러 동작은 보통 편리하고 단점도 거의 없습니다.여러 예외가 있는 경우(예: 실패 시)Parallel
여러 태스크가 실패했을 경우의 루프await
첫 번째 예외를 제외한 모든 예외를 삭제합니다.그러면 디버깅이 어려워집니다.
이러한 접근 방식은 모두 유사한 성능을 가집니다.어떤 식으로든 OS 이벤트를 할당하고 차단합니다.그게 비싼 부분이에요.그것에 비해 다른 기계는 값이 싸다.어떤 방법이 절대적으로 저렴한지 모르겠어요.
예외가 발생하는 경우, 그것이 가장 비싼 부분이 될 것입니다..NET 5에서는 예외는 고속 CPU에서 최대 200,000/초의 속도로 처리됩니다.딥 스택은 더 느리고 태스크 머신은 예외에 비용을 곱하는 경향이 있습니다.예를 들어, 예외를 재설정하지 않고 작업을 차단하는 방법이 있습니다.task.ContinueWith(_ => { }, TaskContinuationOptions.ExecuteSynchronously).Wait();
.
저는 개인적으로Task.Run(() => DoSomethingAsync()).Wait();
패턴은 데드록이 범주적으로 회피되기 때문에 단순하고 다음과 같은 일부 예외를 숨기지 않습니다.GetResult()
숨어있을지도 몰라하지만 너는 사용할 수 있습니다.GetResult()
이거랑 같이.
에 내장된 API 서페이스가 있는 라이브러리를 업데이트하는 중입니다.NET 3.5. 그 결과 모든 방법이 동기화됩니다.API를 변경할 수 없습니다(즉, 반환 값을 태스크로 변환). 모든 발신자를 변경해야 합니다.따라서 동기식으로 비동기 메서드를 호출하는 최선의 방법이 남아 있습니다.
sync-over-async 안티패턴을 실행하는 일반적인 "최적의" 방법은 없습니다.오직 다양한 해커들만이 각각의 단점을 가지고 있다.
오래된 동기 API를 유지하고 비동기 API를 함께 도입하는 것이 좋습니다.Brownfield Async에 관한 MSDN 기사에서 설명한 바와 같이 "boolan argument hack"을 사용하여 이를 수행할 수 있습니다.
먼저 예시의 각 접근법에 관한 문제에 대해 간단히 설명하겠습니다.
ConfigureAwait
에 맞는 것은 '이해'가입니다.await
; 그 이외의 경우는 아무것도 동작하지 않습니다.Result
는 에외 an an an an an an an an로 합니다.AggregateException
가 있는 ; 를 합니다.GetAwaiter().GetResult()
★★★★★★ 。Task.Run
는 스레드 풀 스레드(스위치)에서 코드를 실행합니다.이것은 코드가 스레드 풀 스레드에서 실행될 수 있는 경우에만 가능합니다.RunSynchronously
는 동적 태스크 기반 병렬 처리를 수행할 때 극히 드문 상황에서 사용되는 고급 API입니다.당신은 그런 시나리오에 전혀 속하지 않아요.Task.WaitAll
것은 그냥 의 과제로 하는 것과 .Wait()
.async () => await x
덜 일 뿐이에요.() => x
.- 현재 스레드에서 시작된 작업을 차단하면 교착 상태가 발생할 수 있습니다.
자세한 내용은 다음과 같습니다.
// Problems (1), (3), (6)
result = Task.Run(async () => await task()).ConfigureAwait(false).GetAwaiter().GetResult();
// Problems (1), (3)
result = Task.Run(task).ConfigureAwait(false).GetAwaiter().GetResult();
// Problems (1), (7)
result = task().ConfigureAwait(false).GetAwaiter().GetResult();
// Problems (2), (3)
result = Task.Run(task).Result;
// Problems (3)
result = Task.Run(task).GetAwaiter().GetResult();
// Problems (2), (4)
var t = task();
t.RunSynchronously();
result = t.Result;
// Problems (2), (5)
var t1 = task();
Task.WaitAll(t1);
result = t1.Result;
이러한 방법 대신 기존의 동작 동기 코드를 가지고 있기 때문에 새로운 자연 비동기 코드와 함께 사용해야 합니다.예를 들어, 기존 코드가 사용된 경우WebClient
:
public string Get()
{
using (var client = new WebClient())
return client.DownloadString(...);
}
비동기 API를 추가하려면 다음과 같이 해야 합니다.
private async Task<string> GetCoreAsync(bool sync)
{
using (var client = new WebClient())
{
return sync ?
client.DownloadString(...) :
await client.DownloadStringTaskAsync(...);
}
}
public string Get() => GetCoreAsync(sync: true).GetAwaiter().GetResult();
public Task<string> GetAsync() => GetCoreAsync(sync: false);
또는 를 사용해야 하는 경우HttpClient
「 」 「 」:
private string GetCoreSync()
{
using (var client = new WebClient())
return client.DownloadString(...);
}
private static HttpClient HttpClient { get; } = ...;
private async Task<string> GetCoreAsync(bool sync)
{
return sync ?
GetCoreSync() :
await HttpClient.GetString(...);
}
public string Get() => GetCoreAsync(sync: true).GetAwaiter().GetResult();
public Task<string> GetAsync() => GetCoreAsync(sync: false);
는 논리로 수 .Core
비동기식으로 할 수 sync
파라미터)를 참조해 주세요. ifsync
true
코어 메서드는 이미 실행된 태스크를 반환해야 합니다.동기 API를 사용하여 동기식으로 실행하고 비동기 API를 사용하여 비동기식으로 실행합니다.
최종적으로 동기 API를 폐지할 것을 권장합니다.
AWS S3 SDK 입니다. 예전에는 동기였고, 그 위에 많은 코드를 만들었는데, 지금은 비동기화 되어 있어요.찮아아그그그그그그그 불평해도 얻을 게 없어요. 으로로나나나나나
따라서 앱을 업데이트해야 하며, 앱의 대부분을 비동기화하도록 리팩터링하거나 S3 비동기 API를 동기화처럼 동작하도록 "해킹"하는 옵션이 있습니다.
저는 결국 더 큰 비동기 리팩터링을 하게 될 것입니다. 많은 이점이 있습니다. 하지만 오늘은 더 큰 일이 있어서 동기화 시늉을 하기로 했습니다.
는 " " " 였습니다.ListObjectsResponse response = api.ListObjects(request);
정말 간단한 비동기적 대응이 제겐 효과가 있습니다.Task<ListObjectsV2Response> task = api.ListObjectsV2Async(rq2);
ListObjectsV2Response rsp2 = task.GetAwaiter().GetResult();
순수주의자들이 저를 비난할 수도 있다는 것을 알지만, 현실은 이것이 많은 긴급한 문제들 중 하나일 뿐이고 저는 시간이 한정되어 있기 때문에 절충을 해야 합니다.?? 아니 가 있어?아, 아, 아, 아, 아, 아, 아, 아, 아? ★★★.
비동기 메서드에서 비동기 메서드를 호출할 수 있습니다.[코드] 를 체크합니다.
public ActionResult Test()
{
TestClass result = Task.Run(async () => await GetNumbers()).GetAwaiter().GetResult();
return PartialView(result);
}
public async Task<TestClass> GetNumbers()
{
TestClass obj = new TestClass();
HttpResponseMessage response = await APICallHelper.GetData(Functions.API_Call_Url.GetCommonNumbers);
if (response.IsSuccessStatusCode)
{
var result = response.Content.ReadAsStringAsync().Result;
obj = JsonConvert.DeserializeObject<TestClass>(result);
}
return obj;
}
언급URL : https://stackoverflow.com/questions/40324300/calling-async-methods-from-non-async-code
'programing' 카테고리의 다른 글
WebForms UntruptiveValidationMode를 사용하려면 'jquery'를 위한 ScriptResourceMapping이 필요합니다.jquery(대문자와 소문자가 구분됨)라는 이름의 ScriptResourceMapping을 추가하십시오. (0) | 2023.04.23 |
---|---|
이미 실행 중인 프로세스를 nohup에 넣는 방법은 무엇입니까? (0) | 2023.04.23 |
VBA를 사용하지 않고 Excel에서 역문자열 검색을 실행하는 방법은 무엇입니까? (0) | 2023.04.23 |
T-SQL에는 문자열을 연결하는 집약 기능이 있습니까? (0) | 2023.04.23 |
iOS에서 이메일 주소가 유효한지 확인합니다. (0) | 2023.04.23 |