async & await-대안에 대한 설문 조사 [닫기]


15

c # 5에 무엇이 저장되어 있는지 알았 으므로, 어제 PDC10 에서 Anders Heijsberg가 발표 한 ' Asynchrony '에 대한 두 가지 새로운 키워드의 선택에 영향을 줄 수있는 여지가 여전히 남아 있습니다.

async void ArchiveDocuments(List<Url> urls) {
    Task archive = null;
    for(int i = 0; i < urls.Count; ++i) {
        var document = await FetchAsync(urls[i]);
        if (archive != null)
            await archive;
        archive = ArchiveAsync(document);
    }
}

Eric Lippert 는 현재 두 키워드의 선택과 유용성 연구에서 오해 된 방식에 대해 설명합니다. 의견에는 몇 가지 다른 제안이 있습니다.

답변 당 하나의 제안, 중복이 표시됩니다.


) 그런데 "언어 통합 비동기 프로그래밍"우리 LIAP주는 매우 혀 LINQ와 같은 방법으로 굴러하지 않습니다
Benjol

1
뚜렷한 도약이 아니라면.
콘래드 프릭스

3
그러나 "언어 통합 비동기 런타임"은 훌륭하게 요약됩니다.
glenatron

이것은 주제를 벗어난 것이어야합니다.
DeadMG

답변:


6

의 의미 / 필요성에 대해 명확하지 않다는 점을 감안할 때 async실제로 논쟁 할 수는 없지만 교체를위한 최선의 제안 await은 다음과 같습니다.

yield while (봐! 새로운 키워드 없음)

참고 좀 더 이것에 대해 생각을 가지고, 나는 다시 사용 여부를 궁금해 while이런 방식으로는 좋은 아이디어이다 - 자연적인 경향이 이후 부울을 기대하는 것입니다.

(생각 : 좋은 키워드를 찾는 것은 좋은 도메인 이름을 찾는 것과 같습니다.)


+1 그리고
그건

그러나 작업이 이미 완료된 경우 반드시 실행을 요구하지는 않습니다. 그러나 당신은 항상 과제의 완료를 기다리고 있습니다.
Allon Guralnek

@Allon false while(x) {...}인 경우 루프 본문을 반드시 실행할 필요는 없습니다 x.
자기 자신에 대한 메모-1

@ 참고 :에 동사가 없습니다 while. 와 같은 동사를 추가 do하면 get do {...} while (x)과 함께 x에 관계없이 본문을 실행합니다 (적어도 한 번). 에 대한 당신의 제안은 yield while매우 비슷해 보이지만 do while동사를 수행한다는 반대 보증이 있습니다. 내가 가장 싫어하는 것은 yield메커니즘의 구현을 암시한다는 것입니다. async/의 요점은 await비동기 스타일로 동기식 작업을 작성한다는 것입니다. yield그 동기 스타일을 깨뜨립니다.
Allon Guralnek

새로운 키워드가 반드시 나쁜 것입니까? 내가 이해하는 것처럼 await키워드는 컨텍스트로 인식되므로 원한다면 "await"라는 메서드 나 변수를 계속 사용할 수 있습니다. 어느 정도까지는 새로운 기능을 위해 새로운 키워드를 사용하는 것이 기존 키워드를 재사용하여 하나 이상의 것을 의미하는 것보다 혼란 스럽다고 생각합니다. (과장된 예 : dangermouse.net/esoteric/ook.html )
Tim Goodman

5

키워드가없는 것은 어떻습니까?

컴파일러가 비동기 메소드를 호출 할 때 그 결과를 원한다는 것을 깨닫기를 원합니다.

Document doc = DownloadDocumentAsync();

그게 다야. 사람들이이 문제에 대한 키워드를 생각하는 데 어려움을 겪는 이유는 "일이 완벽하게 정상적으로 이루어 졌다면 할 일"에 대한 키워드를 가지고 있기 때문입니다. 이것이 기본값이어야하며 키워드는 필요하지 않습니다.

최신 정보

필자는 원래 컴파일러가 수행해야 할 작업을 파악하기 위해 형식 유추로 영리해야한다고 제안했습니다. 이것에 대해 더 생각하면 CTP에서 기존 구현을 그대로 유지하지만 몇 가지 간단한 추가를 수행하여 await키워드를 명시 적으로 사용해야하는 경우를 줄 입니다.

우리는 속성을 발명합니다 : [AutoAwait]. 이것은 메소드에만 적용 할 수 있습니다. 이것을 메소드에 적용하는 한 가지 방법은이를 표시하는 것 async입니다. 그러나 직접 수행 할 수도 있습니다. 예 :

[AutoAwait]
public Task<Document> DownloadDocumentAsync()

그런 다음 모든 async메소드에서 컴파일러는에 대한 호출을 기다리고 있다고 가정 DownloadDocumentAsync하므로 지정할 필요가 없습니다. 해당 메소드를 호출하면 자동으로 대기합니다.

Document doc = DownloadDocumentAsync();

이제, "영리하게"하고를 얻으려면 Task<Document>operator를 사용하면 start메소드 호출 전에 만 표시 될 수 있습니다.

Task<Document> task = start DownloadDocumentAsync();

깔끔합니다. 이제 일반 메소드 호출은 일반적으로 의미하는 바를 의미합니다. 메소드가 완료 될 때까지 기다리십시오. 그리고 start다른 것을 나타냅니다 : 기다리지 마십시오.

async메소드 외부에 나타나는 코드의 경우 메소드를 호출 할 수있는 유일한 [AutoAwait]방법은 앞에 접두어를 붙이는 것입니다 start. 이렇게하면 async메소드에 표시되는지 여부에 관계없이 동일한 의미의 코드를 작성하게됩니다 .

욕심이 나기 시작합니다! :)

먼저 async인터페이스 메소드에 적용 하고 싶습니다 .

interface IThing
{
    async int GetCount();
} 

그것은 기본적으로 구현 메소드가 Task<int>또는 호환되는 것을 반환해야 await하며 메소드를 호출하면 [AutoAwait]동작 을 얻습니다 .

또한 위의 방법을 구현할 때 다음과 같이 쓸 수 있기를 원합니다.

async int GetCount()

따라서 Task<int>반환 유형 으로 언급 할 필요가 없습니다 .

또한 async대리자 유형 (결국 하나의 메서드가있는 인터페이스와 유사)에 적용하고 싶습니다. 그래서:

public async delegate TResult AsyncFunc<TResult>();

async대표는이 - 당신은 그것을 짐작 - [AutoAwait]행동. async메소드 에서 호출 할 수 있으며 자동으로 await선택됩니다 (단지 선택하지 않는 한 start). 그리고 당신이 말하면 :

AsyncFunc<Document> getDoc = DownloadDocumentAsync;

그냥 작동합니다. 메소드 호출이 아닙니다. 아직 시작된 작업 async delegate이 없습니다 - 작업이 아닙니다. 작업을 수행하는 공장입니다. 당신은 말할 수 있습니다 :

Document doc = getDoc();

그러면 작업이 시작되고 완료 될 때까지 기다렸다가 결과가 나타납니다. 또는 당신은 말할 수 있습니다 :

Task<Document> t = start getDoc();

따라서 "배관"이 누출되는 곳 중 한 곳은 async메서드에 대리자를 만들려면 async delegate형식 을 사용해야한다는 것 입니다. 따라서 대신 Func에을 말해야합니다 AsyncFunc. 언젠가는 그런 종류의 것이 개선 된 유형 유추에 의해 고정 될 수 있습니다.

또 다른 질문은 일반적인 (비동기 적 인) 방법으로 시작한다고 말하면 어떻게됩니까? 분명히 컴파일 오류가 안전한 옵션입니다. 그러나 다른 가능성이 있습니다.


이것은 암묵적인 변환으로 가능하지만 그렇지 않으면 명령문의 왼쪽에서 오른쪽 평가가 필요합니다 (람다를 제외하고 컴파일러가 정상적으로 작동하는 방식과 정확히 반대입니다). 나는 이것을 사용하지 못하고 var잠재적으로 긴 명시 적 유형 이름을 대체 해야하기 때문에 await누군가가 실수로 정상적인 동기 메소드 대신 비동기 메소드를 호출 한 경우와 모호한 경우 에도 여전히 반대라고 생각 합니다 . 처음에는 직관적 인 것처럼 보이지만 실제로는 가장 놀랍지 않은 원칙을 위반합니다.
Aaronaught

@Aaronaught-왜 사용을 방해 var합니까? 내 답변의 이전 개정판에 응답하는지 궁금합니다. 완전히 다시 작성했습니다. 이제이 제안을 다음과 같이 생각할 수 있습니다. 메소드에 특수 속성이 표시되어 있으면 접두사로 await이를 억제하지 않는 한 키워드가 해당 메소드 호출 앞에 자동으로 삽입되는 것과 같습니다 start. 모든 것이 CTP에서와 똑같이 유지되므로 제대로 var작동합니다.
Daniel Earwicker

실제로 나는 ...이 스레드를 다시 방문하고 거의 정확히 당신이 그것을 편집하기로 결정한 시간에 귀하의 답변에 응답하기로 결정한 것이 이상했습니다. 지금 다시 읽어야합니다 ...
Aaronaught

1
await 키워드의 반전이 마음에 듭니다. 그리고 또한의 3 중 중복을 싫어합니다 public async Task<int> FooAsync().
Allon Guralnek

1
예, 비동기 형식의 접미사 명명 규칙이 무언가 더 공식적으로 캡처 될 수 있음을 나타내는 것으로 보입니다. 기본적으로 "이와 같은 메소드는 특정 방식으로 명명되어야하므로 사람들이 올바르게 호출하는 방법을 알고 있어야합니다"라는 규칙이있는 경우 동일한 규칙을 사용하여 해당 메소드를 특정 방식으로 표시 할 수 있습니다. 제대로 부르도록 도와주세요.
Daniel Earwicker


4

나는 async괜찮다고 생각 하지만 아마도 ASP.NET 비동기 페이지와 연결하기 때문일 수 있습니다.

를 들어 await키워드 내가 선호하는 continue afterresume after.

나는 하지 않습니다 같은 yield의미가 방법이 실제로 실행을 양보하지 않을 수 있도록하기 때문에, 또는 그 변종의; 작업 상태에 따라 다릅니다.


내가 좋아하는 resume after위해 await. 어쩌면 async호출 할 수 있습니다 resumable.
Tim Goodman

난 그냥 원합니다 만 aftercontinue after접근 방식은 강력한 구현 장점이 있습니다 : 그것은 현재 기존의 문맥 키워드를 포함하고 있지만, 현재 사용량와 호환되지 않는 구문. 따라서 추가시 기존 코드가 중단되지 않습니다. 완전히 새로운 키워드를 사용하는 경우 구현시 이전 코드에서 식별자로 단어를 사용하는 데 대처해야하므로 상당히 까다로울 수 있습니다.
Edurne Pascual

3

Eric의 블로그에 댓글을 달았는데 동일한 키워드를 사용하는 데 아무런 문제가 없습니다. async

var data = async DownloadFileAsync(url);

파일을 비동기 적으로 다운로드하고 싶다고 표현하고 있습니다. 여기에는 약간의 중복성이 있습니다. "비동기"는 메서드 이름에 있기 때문에 두 번 나타납니다. 컴파일러는 매우 영리하며 "Async"로 끝나는 메소드가 사실상 비동기 메소드라는 규칙을 감지하고 컴파일 된 코드에 추가 할 수 있습니다. 대신에 그냥 전화하고 싶을 수도 있습니다

var data = async DownloadFile(url);

동기식 호출과 반대로

var data = DownloadFile(url);

도대체 async 키워드가 선언에 있기 때문에 동일한 방법으로 정의 할 수 있어야합니다. 왜 각 메소드 이름에 "Async"를 수동으로 추가해야합니까? 컴파일러가 우리를 위해 할 수 있습니다.


나는 당신이 추가 한 설탕을 좋아하지만 C # 사람들은 아마 그것을하지 않을 것입니다. (FWIW, 속성 이름을 검색 할 때 이미 비슷한 작업을 수행함)
자체 참고 사항

2
그리고 async메소드 의 키워드가 멋지다는 것을 감안할 때 (정확히 이해했다면) 가장 좋은 방법은 제안한 것과 반대의 행동을 취하지 않는지 궁금합니다 : async메소드를 포기하고 사용하십시오. 그들이 현재 가지고있는 곳 await.
Benjol

그것은 가능성이다. 메소드 제거의 비동기 키워드는 실제로 청결을 위해 있습니다. 나는 거기에 보관하는 것을 선호하지만 메소드 이름에 "Async"를 추가 할 필요는 없다. 예를 들어 async Task<Byte[]> DownloadFile(...)오히려 Task<Byte[]> DownloadFileAsync(...)(후자는 컴파일 된 서명이 될 것입니다). 어느 쪽이든 작동합니다.
Mark H

나는 솔직히 이것의 팬이 아닙니다. 이전 의견에서와 같이 최종 버전이 실제로 작성된 것과 완전히 다른 메소드를 호출하기 때문에 최소 놀라움의 원칙을 위반한다는 점을 지적해야하며 해당 메소드의 구현 및 서명은 전적으로 구현 클래스에 달려 있습니다. . 정말 아니기 때문에 심지어 첫 번째 버전은 문제가 말하는 (비동기이 비동기 방법을 실행?) 아무것도. 우리가 표현하려고하는 생각은 계속 되거나 연기 된 처형 이며, 이것이 전혀 표현하지 않습니다.
Aaronaught

3

async = task- 함수를 수정하여 작업을 반환하므로 키워드 "task"를 사용하지 않는 이유는 무엇입니까?

await = finish-기다릴 필요는 없지만 결과를 사용하기 전에 작업을 "완료"해야합니다.


여기서 단순성과 논쟁하기는 정말 어렵습니다.
sblom

2

나는 좋아한다 yield until. yield while이미 제안했듯이 훌륭하고 새로운 키워드를 소개하지 않지만 '정지'가 동작을 조금 더 잘 포착한다고 생각합니다.

yield <something>yield는 이미 나머지 방법을 계속 잘 만드는 아이디어를 포착하기 때문에 좋은 생각 이라고 생각 합니다. 어쩌면 누군가는 "때까지"보다 더 나은 단어를 생각할 수 있습니다.


2

comefromINTERCAL의 COMEFROM 선언 에서 내가 본 첫 번째 용도 로 Aaron G의 제안에 대한 투표를 등록하고 싶습니다 . 아이디어는 (멀리 점프 일종의 GOTO의 반대의 점이다 에서 이 코드 점프에 어떤 장소를 만드는의 GOTO 문) COMEFROM 문.


2

우리는 Task<T>s를 다루기 때문에 다음과 start같이 명령문 앞에 키워드로 사용 하는 것은 어떻 습니까?

start var document = FetchAsync(urls[i]);


흠, 아마도 finish더 나은 것보다 start?
주인공

1

F # async은 비동기 워크 플로에서 키워드를 사용한다는 점에 주목할 가치가 있습니다 . 이는 C # 5의 새로운 비동기 기능과 거의 동일합니다. 그러므로 나는 그 것을 동일하게 유지할 것입니다

awaitF # 의 키워드는 let!대신을 사용 합니다 let. C #에는 동일한 할당 구문이 없으므로 =부호 오른쪽에 무언가가 필요합니다 . Benjol이 말했듯이, 그것은 yield거의 같은 변형이어야합니다.


1
"대기"는 전혀 과제가 될 필요는 없습니다 (물론 일반적으로 가능합니다). GetAwaiter를 찾을 수있는 유형을 가진 거의 모든 표현에 대해 연산자로서 합법적입니다. (정확한 규칙은 아직 출판 가능한 양식으로 작성되지 않았습니다.)
Eric Lippert

1
@Eric, F #에서 그렇 겠지만, do!당신은 그것을 알았습니다 ...
Benjol

1

yield async FetchAsync(..)


이것은 async호출하는 메소드에 적용 해야하는 수정 자 와 완벽하게 일치합니다 . 또한 현재의 의미 yield return, 당신은 반환 하고 ,이 경우는 비동기 방식으로 실행을 산출하고있는 동안 열거 코드에 수익률 실행.

미래에에 다른 용도가있을 것이라고 가정 해 보겠습니다. 대부분 동일한 작업을 수행하기 위해 다른 키워드를 사용하는 대신 x가 빛나는 새로운 기능인 where를 yield추가 할 수 있습니다 yield x.

솔직히 말해서 나는 '실행력을 포기하지 않는다'는 주장을 이해하지 못한다. 결국, 다른 메소드를 호출하는 시점이 이미 해당 메소드에 대한 '수율'이 아닌가? 비동기인지 여부에 관계없이? 여기에 뭔가 빠졌습니까?

그리고 당신을 위해 좋은 경우 async반환 기적하지만 키워드가 방법이 비동기 적으로 실행 것이라는 가능성 기회가 있음을 의미하고 다른 방법으로 실행을 산출 할 거라고한다 필요. 메소드가 실제로 비동기 호출을 수행하는지 여부에 관계없이 메소드가이를 설명해야합니다.

IMO 다양한 '수율이 아닌'사례는 구현 세부 사항이라고 생각합니다. 차라리 언어의 일관성 (즉, 재사용 yield)을 보증하고 싶습니다 .


0

어떻게 약 complete에서와 같이 "나는 작업이 완료 싶다"?

Task<byte[]> downloadTask = DownloadFileAsync(url);
byte[] data = complete downloadTask;

1
왜 공감해야합니까? 최소한 공감 후 자신을 설명하는 것은 예의입니다.
Allon Guralnek

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.