2016-09-02 1 views
2

비동기 작업의 실행 순서와 관련하여 질문이 있습니다.async와 콜백

이해하기 쉽기 때문에 예제로 질문 해 보겠습니다.

https://msdn.microsoft.com/en-us/library/mt674882.aspx의 공식 사례입니다.

async Task<int> AccessTheWebAsync() 
{ 
    HttpClient client = new HttpClient(); 

    //async operation: 
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); 

    // You can do work here that doesn't rely on the string from GetStringAsync. 
    DoWork1(); 

    // The await operator suspends AccessTheWebAsync. 
    string urlContents = await getStringTask; 

    DoWork2(); 

    return urlContents.Length; 
} 

나는 DoWork2client.GetStringAsync의 콜백 말할 수 있습니까?

client.GetStringAsync IF DoWork1이 완료되면 DoWork2이 즉시 실행되지 않고 client.GetStringAsync보다 길게 실행됩니다.

여기 있습니까?

+0

예. 작업을 시작합니다. DoWork1()이 완료되면 작업을 기다리고 있습니다. 이미 완료 되었다면 DoWork2가 즉시 시작됩니다. 그렇지 않으면 작업이 완료되면'DoWork2'가 시작됩니다. –

+0

@AlexanderDerck 그런데 그것은 내가 예상했던 "콜백"과 같은 것이 아닙니다. 내 의견으로는 콜백은 비동기 함수가 완료되면 즉시 실행되어야한다. – derek

+1

DoWork1이 아직 완료되지 않은 경우에도 DoWork2를 실행 (getStringTask 완료시)하고 싶습니까? 어쩌면 [Task.ContinueWith] (https://msdn.microsoft.com/en-us/library/system.threading.tasks.task.continuewith.aspx) 메서드를 살펴보십시오. –

답변

5

DoWork2이 바로 그 시점 await client.GetStrinkAsync에 충돌하면 client.GetStringAsync

보다 client.GetStringAsync 실행 DoWork1 경우 긴 시간의 완료 후 실행되지 않습니다 귀하의 예제에서 같이 보이는, DoWork1()은 이미 완료 실행은 동기식입니다. client.GetStringAsync이 완료되면 DoWork2이 실행되도록 설정됩니다.

실행 흐름이 될 것이다

  1. GetStringAsync 비동기 시작한다. 첫 번째 내부 장치 인 await에 도달 할 때까지 실행 된 다음 AccessTheWebAsync으로 제어를 반환합니다.
  2. DoWork1()가 시작됩니다. 동기식이므로 모두 완료 될 때까지 기다리십시오.
  3. client.GetStringAsync입니다. 비동기 적으로 완료되기 위해이 대기합니다. await은 호출자에게 자연스럽게 실행 제어를 내 보냅니다.
  4. client.GetStringAsync이 완료되면 실행은 AccessTheWebAsync으로 복귀하고 DoWork2()은 동 기적으로 실행됩니다.
  5. urlContents.length이 반환됩니다.

일반적으로 첫 번째 await 키워드 다음의 모든 항목은 나머지 방법에서 계속되도록 설정됩니다.

+0

'DoWork2'를 클라이언트가 즉시 실행하도록 만드는 방법이 있습니까? GetStringAsync'가 끝났습니까? – derek

+0

@derek 그러나 그것은 정확히 무슨 일이 일어나는가입니다. 'client.GetStringAsync'가 완료되면'DoWork2'가 실행됩니다. –

+0

'DoWork1()'은 10 초가 걸리고'client.GetStringAsync'는 5 초가 걸린다. 따라서'client.GetStringAsync'가 끝나면'DoWork1()'이 아직 실행 중이기 때문에'DoWork1()'이 완료 될 때까지 기다려야합니다. 맞습니까? 그리고 나서 5 초 후'DoWork1()'이 끝납니다. 이 시점에서만'DoWork2()'가 작동하기 시작할 수 있습니다. 내가 틀렸다면 나를 바로 잡아라. – derek

-1

에서 다음 기다려온 작업이 완료 될 때까지

//async operation: 
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); 

당신은 방법의 지속은 DoWork1() 동기, 한 번 string urlContents = await getStringTask; 일을 실행 다음 비동기 작업을 실행하고 호출자에게 즉시 반환하는 작업을 일시 중단 만드는 ; 완료되면 프로그램은 DoWork2()과 함께 계속됩니다.

+1

'getStringTask' 블록을 말하는 것은 비동기 메소드를 제대로'대기 '할 때 일어나는 것과 정반대입니다. –

+1

동의 : '일시 중지'또는 '실행 일시 중지'또는 나머지 'AccessTheWebAsync()'를 'getStringTask'의 연속으로 할당하면보다 정확한 사용법입니다. 블록이 잘못되었습니다 (업데이트 됨) – Ahmad

+1

아니요, 작업이 즉시 실행됩니다.'await'이하는 일은 다른 코드 조각이 이미 시작된 Task (또는 다른 기다릴 수있는 것)를 취하는 것이며 아무것도하지 않으면 (작업이 이미 완료된 경우) 작업이 완료 될 때까지 현재 방법의 실행을 일시 중지합니다. 그러나 다시 강조하기 위해, '기다리는 것'은 ** 아무것도 ** 시작하지 않습니다. –

4

Yuval's answer이 정확합니다.

완료 즉시 client.GetStringAsync 일단 실행 DoWork2을 만들 수있는 방법이 있나요 :

는 후속 질문에 대답하려면?

가능합니다. 이 코드의 컨텍스트에 따라 다릅니다. DoWork1DoWork2을 동시에 UI 스레드에서 실행할 수 없습니다 (분명히 한 번에 하나의 스레드 만 한 번에 하나씩 만 수행 할 수 있음). 그러나 이것이 스레드 풀 컨텍스트에서 호출되면 확실하게 둘 다 동시에 실행할 수 있습니다.

그러나 생각을 '콜백'에서 '운영'으로 변경해야합니다. 즉, 이 GetStringAsync의 "콜백"인 것으로 생각하지 마십시오. 대신 다음과 같이 생각하십시오. 나는 수술을 받았습니다 GetStringAsync, 수술을 받았습니다 DoWork2; 그 중 하나를 수행 한 다음 다른 하나를 수행하는 새로운 작업이 필요합니다.

async Task<int> AccessTheWebAsync() 
{ 
    var task = GetStringAndDoWork2Async(); 

    DoWork1(); 

    string urlContents = await task; 

    return urlContents.Length; 
} 
:

async Task<string> GetStringAndDoWork2Async() 
{ 
    HttpClient client = new HttpClient(); 
    var result = await client.GetStringAsync("http://msdn.microsoft.com"); 
    DoWork2(); 
    return result; 
} 

지금 당신은 당신의 높은 수준의 방법으로 그 새로운 작업을 사용할 수 있습니다 : 당신은 당신이 이런 식으로 생각을 이동하면

,이 솔루션은 새로운 작업에 대한 방법을 작성하는 것입니다