Agora que sabemos o que está reservado para o c # 5, aparentemente ainda há uma abertura para influenciarmos a escolha das duas novas palavras-chave para ' Assíncronia ' que foram anunciadas ontem por Anders Heijsberg no PDC10 .
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 tem uma explicação sobre a escolha das duas palavras-chave atuais e a maneira como elas foram mal interpretadas nos estudos de usabilidade. Os comentários têm várias outras proposições.
Por favor - uma sugestão por resposta, duplicatas serão bloqueadas.
Respostas:
Dado que não sou claro sobre o significado / necessidade de
async
, não posso discutir com isso, mas minha melhor sugestão para substituirawait
é:yield while
(veja! sem novas palavras-chave)Note que, pensando um pouco mais sobre isso, pergunto-me se reutilizar
while
dessa maneira é uma boa idéia - a tendência natural seria esperar um boleano posteriormente.(Pensa: encontrar boas palavras-chave é como encontrar bons nomes de domínio :)
fonte
while(x) {...}
, sex
for falso.while
. Se você adicionar um verbo, comodo
, então você obtémdo {...} while (x)
, que executa o corpo independentemente de x (pelo menos uma vez). Sua sugestãoyield while
parece muito semelhantedo while
, mas com garantias opostas de execução do verbo, o que pode ser um pouco enganador (mas não tanto assim). O que mais detestoyield
é que implica a implementação de um mecanismo. O ponto principal deasync
/await
é que você escreve uma operação assíncrona em um estilo síncrono.yield
quebra esse estilo síncrono.await
palavra - chave seria reconhecida pelo contexto, para que você ainda possa ter um método ou variável chamado "aguardar", se desejar. Até certo ponto, acho que usar uma nova palavra-chave para novas funcionalidades é menos confusa do que reutilizar uma palavra-chave existente para significar mais de uma coisa. (exemplo exagerado: dangermouse.net/esoteric/ook.html )Que tal não ter uma palavra-chave?
Gostaria que o compilador percebesse que, na maioria das vezes, quando chamo um método assíncrono, quero o resultado.
É isso aí. A razão pela qual as pessoas estão tendo dificuldade em pensar em uma palavra-chave para isso é porque é como ter uma palavra-chave para "faça o que você faria se as coisas fossem perfeitamente normais". Esse deve ser o padrão, não requer uma palavra-chave.
Atualizar
Originalmente, sugeri que o compilador deveria ficar esperto com a inferência de tipo para descobrir o que fazer. Pensando mais sobre isso, eu manteria a implementação existente no CTP como ela é, mas faria algumas adições triviais, para reduzir os casos em que você precisaria usar a
await
palavra - chave explicitamente.Nós inventamos um atributo:
[AutoAwait]
. Isso só pode ser aplicado a métodos. Uma maneira de aplicar isso ao seu método é marcá-loasync
. Mas você também pode fazer isso manualmente, por exemplo:Então, dentro de qualquer
async
método, o compilador assumirá que você deseja aguardar uma chamadaDownloadDocumentAsync
, para que você não precise especificá-lo. Qualquer chamada para esse método o aguardará automaticamente.Agora, se você deseja "ficar esperto" e obter o
Task<Document>
, use um operadorstart
, que só pode aparecer antes de uma chamada de método:Legal, eu acho. Agora, uma chamada simples de método significa o que normalmente significa: aguarde a conclusão do método. E
start
indica algo diferente: não espere.Para o código que aparece fora de um
async
método, a única maneira de você chamar um[AutoAwait]
método é prefixando-ostart
. Isso obriga a escrever um código com o mesmo significado, independentemente de ele aparecerasync
ou não em um método.Então eu começo a ficar ganancioso! :)
Em primeiro lugar, quero
async
aplicar aos métodos de interface:Basicamente, significa que o método de implementação deve retornar
Task<int>
ou algo compatívelawait
e os chamadores do método terão[AutoAwait]
comportamento.Além disso, quando eu implemento o método acima, desejo poder escrever:
Portanto, não tenho que mencionar
Task<int>
como o tipo de retorno.Além disso, quero
async
aplicar a tipos de delegação (que, afinal, são como interfaces com um método). Então:Um
async
delegado tem - você adivinhou -[AutoAwait]
comportamento. A partir de umasync
método, você pode chamá-lo e ele seráawait
editado automaticamente (a menos que você escolha apenasstart
). E então, se você disser:Isso simplesmente funciona. Não é uma chamada de método. Nenhuma tarefa foi iniciada ainda - uma
async delegate
não é uma tarefa. É uma fábrica para fazer tarefas. Você pode dizer:E isso iniciará uma tarefa, esperará que ela termine e dê o resultado. Ou você pode dizer:
Portanto, um lugar onde o "encanamento" vaza é que, se você deseja fazer um delegado para um
async
método, precisa saber usar umasync delegate
tipo. Então, em vez deFunc
você deve dizerAsyncFunc
, e assim por diante. Embora um dia esse tipo de coisa possa ser corrigido por inferência de tipo aprimorada.Outra pergunta é o que deveria acontecer se você disser iniciar em um método comum (não assíncrono). Obviamente, um erro de compilação seria a opção segura. Mas existem outras possibilidades.
fonte
var
, potencialmente, a necessidade de substituir algum nome de tipo explícito longo e também é ambíguo entre oawait
caso e o caso em que alguém acidentalmente chamou o método assíncrono em vez do método síncrono normal. Parece intuitivo a princípio, mas na verdade viola o princípio da menor surpresa.var
? Gostaria de saber se você está respondendo à revisão anterior da minha resposta ... Eu a reescrevi completamente. Agora você pode pensar nessa sugestão da seguinte maneira: se o método estiver marcado com um atributo especial, é como se aawait
palavra-chave fosse inserida automaticamente na frente das chamadas para esse método (a menos que você a suprima com ostart
prefixo). Tudo permanece exatamente como no CTP e, portanto,var
funciona bem.public async Task<int> FooAsync()
.(se você não conseguir, leia a entrada do blog de Eric . Pelo menos é melhor que
for sooth Romeo wherefore art thou AsyncFetch(…)
)fonte
Eu acho que
async
está bem, mas talvez seja porque eu o associo a páginas assíncronas do ASP.NET - a mesma idéia.Para a
await
palavra - chave eu prefirocontinue after
ouresume after
.Eu não como
yield
ou qualquer de suas variantes, porque a semântica são tais que o método pode nunca realmente deu execução; isso depende do estado da tarefa.fonte
resume after
deawait
. Talvezasync
possa ser chamadoresumable
.after
, acontinue after
abordagem tem uma forte vantagem de implementação: inclui uma palavra-chave contextual existente no momento, mas com uma sintaxe incompatível com o uso atual. Isso garante que a adição nunca irá quebrar o código existente. Ao usar uma palavra-chave totalmente nova, a implementação precisa lidar com os possíveis usos da palavra como um identificador no código mais antigo, o que pode ser bastante complicado.Também adicionei comentários ao blog de Eric, não vejo problemas ao usar a mesma palavra-chave
async
Estou apenas expressando que quero baixar o arquivo de forma assíncrona. Há um pouco de redundância aqui, "async" aparece duas vezes, porque também está no nome do método. O compilador pode ser mais inteligente e detectar a convenção de que os métodos que terminam em "Async" são métodos assíncronos de fato e acrescentam isso para nós no código compilado. Então, em vez disso, você pode querer ligar
em vez de chamar o síncrono
Caramba, também devemos poder defini-los da mesma maneira, já que a palavra-chave assíncrona está presente em nossa declaração, por que devemos adicionar manualmente "Async" a cada nome de método - o compilador pode fazer isso por nós.
fonte
async
palavra-chave no método é apenas uma questão de segurança (se eu entendi corretamente), pergunto-me se a melhor coisa a fazer não seria fazer o oposto do que você sugere: abandoneasync
o método e apenas o use. onde eles estão atualmenteawait
.async Task<Byte[]> DownloadFile(...)
vez deTask<Byte[]> DownloadFileAsync(...)
(a última será a assinatura compilada de qualquer maneira). De qualquer maneira funciona.async = task - Está modificando uma função para retornar uma tarefa. Por que não usar a palavra-chave "task"?
waitit = finish - Não precisamos necessariamente esperar, mas a tarefa precisa "terminar" antes de usar o resultado.
fonte
Eu gosto
yield until
.yield while
, já sugerido, é ótimo e não apresenta novas palavras-chave, mas acho que "até" captura o comportamento um pouco melhor.Eu acho que
yield <something>
é uma ótima idéia, porque o rendimento já captura a idéia de tornar o restante do método uma continuação tão bem. Talvez alguém possa pensar em uma palavra melhor do que "até".fonte
Eu só quero registrar meu voto na sugestão de Aaron G
comefrom
- o primeiro uso apropriado que eu vi da declaração COMEFROM da INTERCAL . A idéia é que é o oposto do GOTO (saltando para longe da instrução GOTO), pois faz com que algum lugar no seu código vá para a instrução COMEFROM.fonte
Como estamos lidando com
Task<T>
s, que tal usarstart
como palavra-chave que precede a declaração, como em:start var document = FetchAsync(urls[i]);
fonte
finish
seria ainda melhor do questart
?Vale ressaltar que o F # também usa a
async
palavra - chave em seus fluxos de trabalho assíncronos, o que é praticamente a mesma coisa que a nova funcionalidade assíncrona no C # 5. Portanto, eu manteria o mesmoPara a
await
palavra - chave em F #, eles apenas usam emlet!
vez delet
. O C # não tem a mesma sintaxe de atribuição, portanto, eles precisam de algo no lado direito do=
sinal. Como Benjol disse, funciona da mesmayield
maneira que deveria ser quase uma variante disso.fonte
do!
, mas você sabia que ...yield async FetchAsync(..)
Isso vai perfeitamente com o
async
modificador que você precisa aplicar no método que está chamando. E também a semântica da corrente,yield return
ou seja, você retorna e produz execução para o código enumerador enquanto, nesse caso, está produzindo sua execução para o método assíncrono.Imagine se, no futuro, houver outros usos para
yield
, poderíamos adicionar um emyield x
que x é o novo recurso brilhante, em vez de termos todas essas palavras-chave diferentes para fazer basicamente a mesma coisa, render execução.Sinceramente, não entendo bem o argumento 'não rendendo execução'. Afinal, o objetivo de chamar outro método já não é 'render execução' para esse método? Independentemente de ser assíncrono ou não? Estou faltando alguma coisa aqui?
E bom para você se o
async
retorno de forma síncrona, mas com a palavra-chave lá, significar que há uma chance provável de que o método seja executado de forma assíncrona e que você esteja produzindo execução para outro método. Seu método deve levar isso em consideração, independentemente de o método realmente fazer chamadas assíncronas ou não.Na IMO, acho que os vários casos "não ceder" são um detalhe de implementação. Eu prefiro garantir a consistência no idioma (ou seja, reutilizar
yield
).fonte
Que tal
complete
, como em "Quero que a tarefa seja concluída"?fonte
task
(para declaração do método) easync
(dentro do corpo do método)fonte