C # 5.0에서 비동기 함수와 일반 함수 사이의 선을 흐리게 처리


10

최근 에 C # 5.0 의 놀라운 비동기 대기 패턴을 충분히 얻을 수없는 것 같습니다 . 여기서 당신은 내 인생되었습니다?

나는 간단한 구문에 완전히 흥분하지만 작은 어려움이 있습니다. 내 문제는 비동기 함수에는 일반 함수와 완전히 다른 선언이 있다는 것입니다. 비동기 함수 만 다른 비동기 함수를 기다릴 수 있기 때문에 오래된 차단 코드를 비동기로 이식하려고 할 때 변환 해야하는 함수의 도미노 효과가 있습니다.

사람들은 이것을 좀비 침입이라고 불렀습니다 . async가 코드에 물린 경우 계속 커지고 커집니다. 포팅 프로세스는 어렵지 않습니다 async. 선언을 던지고 반환 값을로 감싸는 것입니다 Task<>. 그러나 오래된 동기 코드를 이식 할 때이 작업을 반복해서 수행하는 것은 성가신 일입니다.

두 함수 유형 (비동기 및 일반 이전 동기화)이 정확히 동일한 구문을 가지고 있다면 훨씬 더 자연 스러울 것 같습니다. 이 경우 포팅에 아무런 노력이 들지 않으며 두 가지 형식간에 어려움없이 전환 할 수 있습니다.

다음 규칙을 따르면 이것이 효과가 있다고 생각합니다.

  1. 비동기 함수는 async더 이상 선언이 필요하지 않습니다. 반환 유형은에 싸일 필요가 없습니다 Task<>. 컴파일러는 컴파일하는 동안 비동기 함수 자체를 식별하고 필요에 따라 Task <> 줄 바꿈을 자동으로 수행합니다.

  2. 비동기 함수에 대한 더 이상 화재를 잊어 버리지 않습니다. 비동기 함수를 호출하려면 기다려야합니다. 어쨌든 나는 불을 잊어 버리지 않으며 미친 경쟁 조건이나 교착 상태의 모든 예는 항상 그것들을 기반으로하는 것 같습니다. 나는 그들이 우리가 활용하려는 동기식 사고 방식과 너무 혼동되고 "손이 닿지 않는다"고 생각합니다.

  3. 불을 잊지 않고 살 수 없다면 특별한 구문이있을 것입니다. 어쨌든, 그것은 내가 이야기하는 간단한 통합 구문의 일부가 아닙니다.

  4. 비동기 호출을 나타내는 데 필요한 유일한 키워드는 await입니다. 기다리는 경우 호출은 비동기입니다. 그렇지 않으면 호출은 일반 오래된 동기입니다 (더 이상 발사하지 않아도됨을 기억하십시오).

  5. 컴파일러는 더 이상 특별한 선언이 없기 때문에 비동기 함수를 자동으로 식별합니다. 규칙 4를 사용하면이 작업을 매우 간단하게 수행 할 수 있습니다. 함수 await내부에 호출이 있으면 비동기입니다.

이 작동 할 수 있습니까? 아니면 뭔가 빠졌습니까? 이 통일 된 구문은 훨씬 유동적이고 좀비 침입을 완전히 해결할 수 있습니다.

몇 가지 예 :

// assume this is an async function (has await calls inside)
int CalcRemoteBalanceAsync() { ... }

// assume this is a regular sync function (has no await calls inside)
int CalcRemoteBalance() { ... }

// now let's try all combinations and see what they do:

// this is the common synchronous case - it will block
int b1 = CalcRemoteBalance();

// this is the common asynchronous case - it will not block
int b2 = await CalcRemoteBalanceAsync();

// choosing to call an asynchronous function in a synchronous manner - it will block
// this syntax was used previously for async fire-and-forget, but now it's just synchronous
int b3 = CalcRemoteBalanceAsync();

// strange combination - it will block since it's calling a synchronous function
// it should probably show a compilation warning though
int b4 = await CalcRemoteBalance();

참고 : 이것은 SO에서 흥미로운 관련 토론 의 연속입니다.


3
당신은 항상 비동기 작업을 기다리고 있습니까? 해고 한 직후에이 작업을 수행하지 말라고 알려주십시오.
Jimmy Hoffa

1
또한 비동기의 가장 큰 장점 중 하나는 바로 할 필요가 없다는 것 await입니다. 당신은 같은 것을 할 수 있습니다 var task = FooAsync(); Bar(); await task;. 제안서에서 어떻게해야합니까?
svick

3
그래서 토론이 있습니까? 어디 내 BFG-3000 ...의
로버트 하비

2
@talkol 병렬 프로그래밍이 음란하다고 생각하십니까? 말할 때 가장 흥미로운 것은 흥미로운 전망 async입니다. 나는 그의 가장 큰 장점 중 하나라고 생각 async- await: 그것은 당신이 쉽게 작성 비동기 작업을 할 수 있다는 것 (뿐 아니라 간단한의 방법 "A, A의 대기를 시작, B, B에 대한 대기 시작"). 그리고 이미이 목적을위한 특별한 구문이 있습니다 await.
svick

1
@ svick haha, 지금 우리는 거기에 갔다 :) 나는 병렬 프로그램이 음란하다고 생각하지 않지만 async-await로 그것을하는 것이 생각합니다. Async-await는 차단 가격을 지불하지 않고 동기 상태를 유지하기위한 구문 설탕입니다. 이미 병렬로 생각하는 경우에, 나는 다른 패턴을 사용하도록 촉구
talkol

답변:


9

귀하의 질문은 이미 귀하가 연결 한 SO 질문에 답변되어 있습니다.

async / await의 목적은 대기 시간이 긴 작업이 많은 세계에서 코드를보다 쉽게 ​​작성할 수 있도록하는 것입니다. 대부분의 작업은 높은 대기 시간 이 아닙니다 .

WinRT가 처음 나왔을 때 설계자들은 어떤 작업이 비 동기화 될지 어떻게 결정했는지 설명했습니다. 그들은 50ms 이상 걸리는 것은 비동기 적이며 나머지 메소드는 일반적인 비동기식 메소드라고 결정했다.

비 동기화하기 위해 몇 개의 메소드를 다시 작성해야합니까? 그들 중 약 10 %. 다른 90 %는 전혀 영향을받지 않았습니다.

Eric Lippert는 한 가지 크기의 접근 방식을 채택하지 않은 이유를 상당히 실질적인 기술적 세부 사항으로 설명합니다. 그는 기본적으로 말한다 asyncawait계속 통과 스타일의 부분적인 구현으로, 경우에 맞게 이러한 스타일을 최적화하는 것은 어려운 문제가 있음.


SO 질문과이 질문의 실질적인 차이점에 유의하십시오. SO는 왜 모든 것을 비 동기화하지 않는지 묻습니다. 여기서는 동일한 구문을 사용하여 10 % 비 동기화하는 것이 좋습니다. 보다 쉽게 할 수있는 장점을 자세히 구문이 사용 변경 10 %가 비동기 인 고통 도미노 이러한 변화의 영향없이,
talkol

async좀비 침입이 발생 하는지 는 불분명합니다 . 메소드가 10 개의 다른 메소드를 호출하더라도 async최상위 레벨 만 필요하지 않습니까?
Robert Harvey

6
현재 코드의 100 %가 동기화되었다고 가정하겠습니다. 이제 비동기로 변경하려는 DB를 쿼리하는 단일 내부 리프 수준 함수가 있습니다. 이제 비 동기화하려면 호출자가 비동기가되고 호출자가 비동기가되어야합니다. 물론 전체 체인이
대기
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.