방금 .Net 4.5에서 async / await로 놀기 시작했습니다. 내가 처음 궁금한 점은 왜 비동기 키워드가 필요한가? 내가 읽은 설명은 마커가 마커이므로 메소드가 무언가를 기다리는 것을 알고 있습니다. 그러나 컴파일러는 키워드없이 이것을 알아낼 수 있어야합니다. 그럼 또 뭐 해요?
방금 .Net 4.5에서 async / await로 놀기 시작했습니다. 내가 처음 궁금한 점은 왜 비동기 키워드가 필요한가? 내가 읽은 설명은 마커가 마커이므로 메소드가 무언가를 기다리는 것을 알고 있습니다. 그러나 컴파일러는 키워드없이 이것을 알아낼 수 있어야합니다. 그럼 또 뭐 해요?
답변:
여기에는 몇 가지 답변이 있으며 모두 비동기 메소드의 기능에 대해 이야기하지만 아무도 대답하지 않으므로 async함수 선언에 사용되는 키워드로 필요합니다.
"컴파일러가 특수한 방식으로 함수를 변환하도록 지시하지는 않습니다"; await혼자 할 수 있습니다. 왜? C #에는 메소드 본문에 특수 키워드가 있으면 컴파일러가 메소드 본문에서 극단적 인 (그리고 매우 유사한 async/await) 변환 을 수행하는 또 다른 메커니즘이 이미 있습니다 yield.
즉 제외하고 yieldC #에서 자신의 키워드 아니며, 그 이유를 설명합니다 이해 async뿐만 아니라. 이 메커니즘을 지원하는 대부분의 언어와는 달리, C #으로는 말할 수 없다 yield value;당신은 말을 yield return value;대신. 왜? C #이 존재 한 후에 언어에 추가 되었기 때문에 어딘가에 누군가 yield가 변수의 이름으로 사용했다고 가정하는 것이 합리적 입니다. 그러나 <variable name> return구문 적으로 올바른 기존 시나리오가 없기 때문에 yield return기존 코드와 100 % 이전 버전과의 호환성을 유지하면서 생성기를 도입 할 수 있도록 언어에 추가되었습니다.
그리고 이것이 변수 이름으로 async사용 된 기존 코드가 깨지지 않도록 함수 수정 자로 추가 된 이유 await입니다. async메소드가 이미 존재 하지 않기 때문에 이전 코드가 무효화되지 않고 새 코드에서 컴파일러는 async태그 의 존재를 사용하여 await식별자가 아닌 키워드로 취급되어야 함 을 알 수 있습니다.
async키워드 를 지정하기위한 요구 사항을 제거 할 수 있습니까? 분명히 BC 붕괴 일 것이지만, 프로젝트 수에 영향을 미치며 업그레이드하기위한 간단한 요구 사항 (예 : 변수 이름 변경)으로 생각할 수 있습니다.
코드 생성을 위해 완전히 다른 접근법이 필요한 콜백이있는 객체로 메소드를 일반 메소드에서 변경합니다.
그런 과감한 일이 발생하면 그것을 명확하게 나타내는 것이 관례입니다 (C ++에서 그 교훈을 배웠습니다)
asyncs를 동시에 예약하고 싶을 때 마다 서로 실행되지 않고 동시에 실행됩니다 (스레드가 사용 가능한 경우)
Task<T>실제로 메소드 의 특성을 갖는 것은 아닙니다. async예를 들어, 비즈니스 / 공장 로직을 실행 한 다음 리턴 하는 다른 메소드에 위임 할 수 있습니다 Task<T>. async메소드는 서명Task<T> 에 리턴 유형이 있지만 실제로 a를 리턴 하지는 않고 단지 a를 리턴합니다 . 키워드 없이이 모든 것을 알아 내기 위해 C # 컴파일러는 메소드에 대한 모든 종류의 심층 검사를 수행해야하는데, 이로 인해 속도가 다소 느려질 수 있으며 모든 모호한 방식으로 이어질 수 있습니다. Task<T>Tasync
"비동기"또는 "안전하지 않은"과 같은 키워드를 사용하는 아이디어는 수정 한 코드를 어떻게 처리해야하는지에 대한 모호성을 제거하는 것입니다. async 키워드의 경우 수정 된 메소드를 즉시 리턴 할 필요가없는 것으로 처리하도록 컴파일러에 지시합니다. 이를 통해이 메소드가 사용 된 스레드가 해당 메소드의 결과를 기다리지 않고 계속할 수 있습니다. 효과적으로 코드 최적화입니다.
좋아, 여기 내가 가져 가라.
뭔가라는이 코 루틴 수십 년 동안 알려져있다. ( "Knuth and Hopper"클래스 "수십 년 동안") 이들은 서브 루틴의 일반화입니다 . 예를 들어 함수 시작 및 리턴 명령문에서 제어를 가져오고 해제 할뿐만 아니라 특정 지점 ( 서스펜션 지점 ) 에서도 제어를 수행합니다 . 서브 루틴은 서스펜션 지점이없는 코 루틴입니다.
"프로토스 레드"에 대한 다음 백서에서 볼 수 있듯이 C 매크로로 쉽게 구현할 수 있습니다. ( http://dunkels.com/adam/dunkels06protothreads.pdf ) 읽어보십시오. 기다릴게...
이것의 결론은 매크로가 큰 만들 것입니다 switch, 그리고 case각각의 서스펜션 점에서 레이블을. 각 서스펜션 지점에서이 함수는 다음 case레이블 의 값을 저장 하므로 다음에 호출 할 때 실행을 재개 할 위치를 알 수 있습니다. 그리고 그것은 발신자에게 제어권을 돌려줍니다.
이것은 "프로토스 레드"에 설명 된 코드의 명백한 제어 흐름을 수정하지 않고 수행됩니다.
이 모든 "프로토스 레드"를 차례로 호출하는 큰 루프가 있고 단일 스레드에서 "프로토스 레드"를 동시에 실행한다고 상상해보십시오.
이 방법에는 두 가지 단점이 있습니다.
두 가지 모두에 대한 해결 방법이 있습니다.
매크로와 해결 방법이 수행하는 재 작성 작업을 수행하도록 컴파일러를 지원했다면 의도 한대로 프로토스 레드 코드를 작성하고 키워드로 서스펜션 포인트를 삽입 할 수 있습니다.
그리고 이것은 무엇 async및 await생성 (스택리스) 코 루틴 : 모든 약이 있습니다.
C #의 코 루틴은 (generic 또는 non-generic) class의 객체로 구체화됩니다 Task.
이러한 키워드는 매우 오해의 소지가 있습니다. 내 정신 독서는 다음과 같습니다
async "필수"로await "완료까지 일시 중단"으로Task "미래…"지금. 함수를 표시해야 async합니까? 함수를 코 루틴으로 만들기 위해 코드 다시 작성 메커니즘을 트리거해야한다는 말과는 별도로 일부 모호성을 해결합니다. 이 코드를 고려하십시오.
public Task<object> AmIACoroutine() {
var tcs = new TaskCompletionSource<object>();
return tcs.Task;
}
async필수가 아니라고 가정하면 , 이것이 코 루틴입니까 아니면 정상적인 기능입니까? 컴파일러가이를 코 루틴으로 다시 작성해야합니까? 둘 다 다른 의미론으로 가능할 수 있습니다.