[C#] 비동기 메서드를 동 기적으로 호출

나는이 async방법을 :

public async Task<string> GenerateCodeAsync()
{
    string code = await GenerateCodeService.GenerateCodeAsync();
    return code;
}

이 메소드를 동기 메소드에서 호출해야합니다.

GenerateCodeAsync이것이 동 기적으로 작동하기 위해 메소드 를 복제하지 않고 어떻게 할 수 있습니까?

최신 정보

그러나 합리적인 해결책을 찾지 못했습니다.

그러나 HttpClient이미이 패턴을 구현하고 있음을 알았습니다.

using (HttpClient client = new HttpClient())
{
    // async
    HttpResponseMessage responseAsync = await client.GetAsync(url);

    // sync
    HttpResponseMessage responseSync = client.GetAsync(url).Result;
}



답변

Result작업 의 속성에 액세스 할 수 있으며 결과를 사용할 수있을 때까지 스레드가 차단됩니다.

string code = GenerateCodeAsync().Result;

참고 : 경우에 따라 교착 상태가 발생할 수 있습니다 Result. 메인 스레드를 차단하면 나머지 비동기 코드가 실행되지 않습니다. 이런 일이 발생하지 않도록하려면 다음과 같은 옵션이 있습니다.

이것은 하지 않습니다 그냥 아무 생각없이 추가해야한다는 것을 의미 .ConfigureAwait(false)모든 비동기 호출 후! 사용시기 및시기에 대한 자세한 분석 .ConfigureAwait(false)은 다음 블로그 게시물을 참조하십시오.


답변

대기자 ( GetAwaiter())를 확보하고 비동기 타스크 ( GetResult()) 의 완료 대기를 종료해야합니다 .

string code = GenerateCodeAsync().GetAwaiter().GetResult();


답변

델리게이트, 람다 표현을 사용 하여이 작업을 수행 할 수 있어야합니다

private void button2_Click(object sender, EventArgs e)
    {

        label1.Text = "waiting....";

        Task<string> sCode = Task.Run(async () =>
        {
            string msg =await GenerateCodeAsync();
            return msg;
        });

        label1.Text += sCode.Result;

    }

    private Task<string> GenerateCodeAsync()
    {
        return Task.Run<string>(() => GenerateCode());
    }

    private string GenerateCode()
    {
        Thread.Sleep(2000);
        return "I m back" ;
    }


답변

이 메소드를 동기식 메소드에서 호출해야합니다.

다른 대답에서 알 수 있듯이 GenerateCodeAsync().Result또는로 가능 GenerateCodeAsync().Wait()합니다. GenerateCodeAsync완료 될 때까지 현재 스레드를 차단합니다 .

그러나 귀하의 질문에 태그가 지정되었습니다 , 그리고 당신은 또한 의견을 남겼습니다 :

asp.net이 많은 코드 줄을 작성하는 것보다 훨씬 쉽게 처리 할 수 ​​있다고 생각하면서 더 간단한 솔루션을 원했습니다.

요점은 ASP.NET의 비동기 메서드를 차단해서는 안된다는 것 입니다. 이렇게하면 웹 앱의 확장 성이 줄어들고 교착 상태가 발생할 수 있습니다 ( await내부 에 연속 GenerateCodeAsync이 게시 될 때 AspNetSynchronizationContext). 사용 Task.Run(...).Result이 특정 HTTP 요청을 처리하기 위해 하나 이상의 스레드를 초래으로 풀 스레드 다음 블록에 오프로드 뭔가하면, 더 많은 확장 성에게조차 상처를합니다.

ASP.NET을 통해 직접 비동기 컨트롤러를 통해 (웹 API ASP.NET MVC와) 중 하나, 비동기 메서드에 대한 지원 내장 또는했다 AsyncManagerPageAsyncTask고전 ASP.NET에서. 사용해야합니다. 자세한 내용은 이 답변을 확인 하십시오 .


답변

Microsoft Identity에는 비동기 메서드를 동 기적으로 호출하는 확장 메서드가 있습니다. 예를 들어 GenerateUserIdentityAsync () 메서드와 동일한 CreateIdentity ()가 있습니다

UserManagerExtensions.CreateIdentity ()를 보면 다음과 같습니다.

 public static ClaimsIdentity CreateIdentity<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user,
        string authenticationType)
        where TKey : IEquatable<TKey>
        where TUser : class, IUser<TKey>
    {
        if (manager == null)
        {
            throw new ArgumentNullException("manager");
        }
        return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType));
    }

이제 AsyncHelper.RunSync의 기능을 살펴 보겠습니다.

  public static TResult RunSync<TResult>(Func<Task<TResult>> func)
    {
        var cultureUi = CultureInfo.CurrentUICulture;
        var culture = CultureInfo.CurrentCulture;
        return _myTaskFactory.StartNew(() =>
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = cultureUi;
            return func();
        }).Unwrap().GetAwaiter().GetResult();
    }

따라서 이것은 비동기 메소드의 래퍼입니다. 그리고 결과에서 데이터를 읽지 마십시오. ASP에서 코드를 잠재적으로 차단합니다.

나에게는 의심스러운 또 다른 방법이 있지만, 당신도 그것을 고려할 수 있습니다

  Result r = null;

            YourAsyncMethod()
                .ContinueWith(t =>
                {
                    r = t.Result;
                })
                .Wait();


답변

교착 상태를 방지하기 위해 Task.Run()@Heinzi가 언급 한 비동기 메소드를 동 기적으로 호출해야 할 때 항상 사용하려고 합니다.

그러나 비동기 메소드가 매개 변수를 사용하는 경우 메소드를 수정해야합니다. 예를 들어 Task.Run(GenerateCodeAsync("test")).Result오류가 발생합니다.

인수 1 : ‘ System.Threading.Tasks.Task<string>‘에서 ‘System.Action’으로 변환 할 수 없습니다

대신 다음과 같이 호출 할 수 있습니다.

string code = Task.Run(() => GenerateCodeAsync("test")).Result;


답변

이 스레드에 대한 대부분의 답변은 복잡하거나 교착 상태가 발생합니다.

다음 방법은 간단하며 작업이 끝날 때까지 기다렸다가 결과를 얻기 때문에 교착 상태를 피할 수 있습니다.

var task = Task.Run(() => GenerateCodeAsync());
task.Wait();
string code = task.Result;

또한 여기에 정확히 동일한 내용에 대해 이야기하는 MSDN 기사에 대한 참조가
있습니다. 기본 문맥 /