zaman uyumsuz ve bekliyor - alternatifler için anket [kapalı]


15

Şimdi c 5. için deposunda ne olduğunu biliyoruz, görünüşe göre hala bize 'için iki yeni anahtar kelimelerin seçimi etkilemek için, bir açıklık vardır asenkroni dün Anders Heijsberg tarafından açıklandı' 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'in mevcut iki anahtar kelimenin seçimi ve kullanılabilirlik çalışmalarında yanlış anlaşılma biçimleri hakkında bir açıklaması vardır. Yorumların başka önerileri var.

Lütfen - cevap başına bir öneri, kopyalar nuked olacak.


Bu arada "dile entegre asenkron programlama" bize LIAP verir, LINQ ile aynı şekilde dili
yitirmez

1
Belirgin bir sıçrama olmadığı sürece.
Conrad Frix

3
Ama "Dil ile Bütünleşik Asenkron Çalışma Zamanı" kısaltmalar güzel.
glenatron

Bu konu dışı olmalı.
DeadMG

Yanıtlar:


6

Bunun anlamı / gerekliliği hakkında net olmadığım göz önüne alındığında async, bununla gerçekten tartışamam, ancak değiştirmek için en iyi önerim await:

yield while (bak! yeni anahtar kelime yok)

Not biraz daha bu konuda düşünce sahip, ben yeniden kullanarak olup olmadığını merak whilebu yolla iyi bir fikirdir - Doğal eğilim sonradan bir boolean beklemek olacaktır.

(Düşünüyor: iyi anahtar kelimeler bulmak, iyi alan adları bulmak gibidir :)


+1 ve bu arada, blog girişine 7 dakika boyunca yorum yapmak için beni dövüyorsun ...
Kendine not -

Ancak, görev zaten tamamlanmışsa, yürütme işlemi yapmanız gerekmez. Ama her zaman görevin tamamlanmasını bekliyorsun (asla beklemese de).
Allon Güralnek

@Allon Yanlışsa, while(x) {...}ikisinin de döngü gövdesini çalıştırmanız gerekmez x.
Kendine not -

@Not: İçinde fiil yok while. Eğer bir fiil eklerseniz gibi do, o zaman olsun do {...} while (x)(bir kez en az) x bakılmaksızın yürütür vücudu işlevi gören. Öneriniz yield whileçok benzer görünüyor do while, ancak fiili yerine getirmenin tersi garantileri var, bu biraz yanıltıcı olabilir (ancak çok fazla değil). En çok sevmediğim şey yield, bir mekanizmanın uygulanmasını gerektirmesidir. async/ Öğesinin tüm noktası, awaitsenkronize bir tarzda eşzamansız bir işlem yazmanızdır. yieldbu eşzamanlı stili kırıyor.
Allon Güralnek

Yeni bir anahtar kelime mutlaka kötü bir şey midir? Anladığım kadarıyla, awaitanahtar kelime içeriğe göre tanınır, böylece isterseniz "beklemek" adında bir yöntem veya değişkeniniz olabilir. Bir dereceye kadar, yeni işlevsellik için yeni bir anahtar kelime kullanmak, mevcut bir anahtar kelimeyi birden fazla şey ifade etmek için yeniden kullanmaktan daha az karmaşıktır. (abartılı örnek: dangermouse.net/esoteric/ook.html )
Tim Goodman

5

Anahtar kelimeye sahip olmamaya ne dersiniz?

Derleyicinin çoğu zaman, eşzamansız bir yöntem çağırdığımda bunun sonucunu istediğini fark etmesini istiyorum.

Document doc = DownloadDocumentAsync();

Bu kadar. İnsanların bu şey için bir anahtar kelime düşünmekte zorlanmasının nedeni, "işler tamamen normal olsaydı yapacağınız şeyi yapmak" için bir anahtar kelimeye sahip olmak gibidir. Bu bir anahtar kelime gerektirmeyen, varsayılan olmalıdır.

Güncelleme

Başlangıçta derleyicinin ne yapacağını anlamak için tür çıkarımı ile akıllı olması gerektiğini önerdim. Bunun hakkında daha fazla düşünmek gerekirse, mevcut uygulamayı olduğu gibi CTP'de de saklıyorum, ancak awaitanahtar kelimeyi açıkça kullanmanız gereken durumları azaltmak için birkaç önemsiz ekleme yapıyorum .

Biz bir öznitelik icat: [AutoAwait]. Bu yalnızca yöntemlere uygulanabilir. Bunun yönteminize uygulanmasını sağlamanın bir yolu onu işaretlemektir async. Ancak bunu elle de yapabilirsiniz, örneğin:

[AutoAwait]
public Task<Document> DownloadDocumentAsync()

Daha sonra async, herhangi bir yöntemin içinde , derleyici bir çağrıyı beklemek istediğinizi varsayar DownloadDocumentAsync, bu yüzden belirtmeniz gerekmez. Bu yönteme yapılan her çağrı otomatik olarak bekler.

Document doc = DownloadDocumentAsync();

Şimdi, "zekice olsun" ve elde etmek Task<Document>istiyorsanız start, yalnızca bir yöntem çağrısından önce görünebilen bir operatör kullanırsınız :

Task<Document> task = start DownloadDocumentAsync();

Temiz, sanırım. Şimdi düz bir yöntem çağrısı genellikle ne anlama gelir: yöntemin tamamlanmasını bekleyin. Ve startfarklı bir şey gösterir: beklemeyin.

Bir asyncyöntemin dışında görünen kod için, bir yöntemi çağırmanıza izin vermenin tek yolu [AutoAwait]öneki eklemektir start. Bu, bir asyncyöntemde görünüp görünmediğine bakılmaksızın aynı anlama gelen kodu yazmaya zorlar .

Sonra açgözlü olmaya başladım! :)

Öncelikle asyncarayüz yöntemlerine başvurmak istiyorum :

interface IThing
{
    async int GetCount();
} 

Temel olarak, uygulama yönteminin geri dönmesi Task<int>veya uyumlu bir şey olması gerektiği anlamına gelir awaitve yönteme çağrı yapanlar [AutoAwait]davranış kazanacaktır .

Ayrıca yukarıdaki yöntemi uygularken, yazmak mümkün olmak istiyorum:

async int GetCount()

Bu yüzden Task<int>dönüş türü olarak bahsetmek zorunda değilim .

Ayrıca, asyncdelege türlerine (sonuçta, bir yöntemle arabirimler gibidir) uygulamak istiyorum. Yani:

public async delegate TResult AsyncFunc<TResult>();

Bir asyncdelege - tahmin ettiniz - [AutoAwait]davranışı var. Bir asyncyöntemden onu çağırabilirsiniz ve otomatik olarak awaitdüzenlenir (yalnızca seçmezseniz start). Ve eğer derseniz:

AsyncFunc<Document> getDoc = DownloadDocumentAsync;

Sadece işe yarıyor. Bu bir yöntem çağrısı değil. Henüz herhangi bir görev başlatılmadı - async delegatebir görev değil. Görev yapmak için bir fabrika. Söyleyebilirsin:

Document doc = getDoc();

Ve bu bir görev başlatacak ve bitmesini bekleyip size sonuç verecektir. Veya şöyle diyebilirsiniz:

Task<Document> t = start getDoc();

Yani "sıhhi tesisat" sızıntı bu yerde bir yer bir asyncyönteme delege yapmak istiyorsanız, bir async delegatetür kullanmayı bilmek zorunda olmasıdır . Yani yerine Funcsöylemelisin AsyncFunc, vb. Bir gün bu tür şeyler geliştirilmiş tür çıkarımıyla düzeltilebilir.

Başka bir soru, sıradan (asenkron olmayan) bir yöntemle başla derseniz ne olması gerektiğidir. Açıkçası derleme hatası güvenli bir seçenek olacaktır. Ancak başka olasılıklar da var.


Bu, örtük bir dönüştürme ile yapılabilir, ancak aksi halde ifadenin soldan sağa değerlendirilmesini gerektirir (bu, lambdas hariç derleyicinin normal olarak nasıl çalıştığının tam tersidir). Ben hala buna karşı olacağını düşünüyorum çünkü varpotansiyel olarak bazı uzun açık tip adını değiştirmek zorunda ve aynı zamanda awaitbiriyle yanlışlıkla eşzamanlı yöntemi yerine normal eşzamanlı yöntem denilen durumda arasında belirsiz . İlk başta sezgisel görünüyor, ancak aslında en az sürpriz ilkesini ihlal ediyor.
Aaronaught

@Aaronaught - Neden kullanılmasını engelliyor var? Cevabımın önceki revizyonuna cevap verip vermediğinizi merak ediyorum ... Tamamen yeniden yazdım. Artık bu öneriyi aşağıdaki gibi düşünebilirsiniz: yöntem özel bir öznitelikle işaretlenmişse, awaitanahtar kelime bu yönteme yapılan çağrıların önüne otomatik olarak eklenir (bunu startönekle bastırmadıkça ). Her şey CTP'de olduğu gibi kalır ve bu nedenle variyi çalışır.
Daniel Earwicker

Gerçekten de ... bu konuyu tekrar gözden geçirmeye ve cevabınızı hemen hemen aynı zamanda düzenlemeye karar verdiğinize yanıtlamaya karar verdim. Şimdi tekrar
okumam gerekecek

1
Bekleyen anahtar kelimeyi tersine çevirmenizi seviyorum. Ve aynı zamanda üçlü fazlalıktan da hoşlanmıyorum public async Task<int> FooAsync().
Allon Güralnek

1
Evet, Async-postfix adlandırma kuralının bir şeyin daha resmi olarak yakalanabileceğinin bir işareti olduğunu görüyorum. Temel olarak, "bunun gibi yöntemlerin belirli bir şekilde adlandırılması gerekir, bu yüzden insanlar bunları nasıl doğru şekilde arayacaklarını bilirler" diyen bir kural varsa, bu kuralın bu yöntemleri belirli bir şekilde ilişkilendirmek için kullanılabileceği ve ardından derleyicinin Onları doğru şekilde aramanıza yardımcı olun.
Daniel Earwicker


4

Bence asynciyi, ama belki de ASP.NET zaman uyumsuz sayfaları ile ilişkilendirmek çünkü - aynı fikir.

İçin awaitanahtar kelime ben tercih continue afterveya resume after.

Anlamlarını sevmiyorum ya da herhangi bir varyantını sevmiyorum , çünkü anlambilim, yöntemin asla gerçekte yürütme sağlayamayacağıyield şekildedir; görevin durumuna bağlıdır.


Sevdiğim resume afteriçin await. Belki asyncaranabilir resumable.
Tim Goodman

Sadece tercih etsem afterde, continue afteryaklaşımın güçlü bir uygulama avantajı var: şu anda var olan bağlamsal bir anahtar kelimeyi içeriyor, ancak mevcut kullanımla uyumlu olmayan bir sözdizimi içeriyor. Bu, eklemenin mevcut kodu asla kırmayacağını garanti eder. Tamamen yeni bir anahtar kelime kullanırken, uygulamanın eski kodda tanımlayıcı olarak sözcüğün olası kullanımlarıyla başa çıkması gerekir, bu da oldukça zor olabilir.
Edurne Pascual

3

Eric'in blogundaki yorumlara da ekledim, aynı anahtar kelimeyi kullanırken herhangi bir sorun görmüyorum async

var data = async DownloadFileAsync(url);

Sadece dosyayı eşzamansız olarak indirmek istediğimi ifade ediyorum. Burada biraz tekrarlama var, "async" iki kez görünüyor, çünkü yöntem adında da var. Derleyici ekstra zekice olabilir ve "Async" ile biten yöntemlerin gerçek zamanlı async yöntemleri olduğu ve bunu bizim için derlenmiş kodda ekleyeceği konvansiyonunu tespit edebilir. Bunun yerine sadece aramak isteyebilirsiniz

var data = async DownloadFile(url);

zaman uyumlu olanı çağırmak yerine

var data = DownloadFile(url);

Heck, aynı şekilde tanımlayabilmeliyiz, çünkü async anahtar sözcüğü bildirimizde var, neden her yöntem adına manuel olarak "Async" eklemeliyiz - derleyici bunu bizim için yapabilir.


Eklediğiniz şekeri seviyorum, ancak C # adamları muhtemelen bunun için gitmeyecek. (FWIW, özellik adlarını ararken benzer bir şey zaten yapıyorlar)
Kendine not -

2
Ve asyncyöntem üzerindeki anahtar kelimenin sadece bir incelik (doğru anladıysam) göz önüne alındığında, en iyi şeyin önerdiğinizin tersini yapmak olup olmayacağını merak ediyorum: asyncyöntemi terk et ve sadece kullan şu anda sahip oldukları yer await.
Benjol

Bu bir olasılık. Yöntem delcaration async anahtar kelime gerçekten temizlik için orada. Ben orada tutmayı tercih ederdim, ama yöntem isimlerine "Async" eklememiz gerekmiyor. Örneğin async Task<Byte[]> DownloadFile(...)yerine Task<Byte[]> DownloadFileAsync(...)(İkincisi yine de derlenmiş imza olacaktır). Her iki şekilde de çalışır.
Mark H

Ben de bunun hayranı değilim. Önceki bir yorumda olduğu gibi, son versiyonunuzun en az sürpriz ilkesini ihlal ettiğine dikkat çekmeliyim, çünkü aslında yazılmış olandan tamamen farklı bir yöntem çağırıyor ve bu yöntemin uygulanması ve imzası tamamen uygulayıcı sınıfa bağlı. . İlk sürüm bile sorunlu çünkü gerçekten bir şey söylemiyor (asenkron olarak bu asenkron yöntemi çalıştırıyor mu?). İfade etmeye çalıştığımız düşünce bir devam ya da ertelenmiş yürütmedir ve bu hiç de ifade etmez.
Aaronaught

3

async = görev - Görevi döndürmek için bir işlevi değiştiriyor, neden "görev" anahtar sözcüğünü kullanmıyorsunuz?

await = finish - Beklememiz gerekmiyor, ancak görev sonucu kullanmadan önce "bitirmek" zorunda.


Buradaki basitlikle tartışmak gerçekten zor.
sblom

2

Sevdim yield until. yield while, zaten önerildi, harika ve yeni bir anahtar kelime getirmiyor, ancak "kadar" davranışı biraz daha iyi yakaladığını düşünüyorum.

Bence yield <something>harika bir fikir, çünkü verim zaten yöntemin geri kalanını bu kadar iyi bir devam ettirme fikrini yakalar. Belki birisi "kadar" kelimesinden daha iyi bir kelime düşünebilir.


2

Aaron G'nin önerisi için oyumu kaydetmek istiyorum comefrom- INTERCAL'in COMEFROM ifadesinde gördüğüm ilk uygun kullanım . Fikir (uzakta atlama sıralama GOTO tam tersi olmasıdır dan sizin kod atlamada bazı yer yapar ki GOTO deyimi) için derzlerinde deyimi.


2

Task<T>S ile uğraştığımızdan start, ifadeden önce bir anahtar kelime olarak şu şekilde kullanılır:

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


Hmmm, belki finishdaha da iyi olurdu start?
Kahraman

1

F # 'ın aynı zamanda asyncC # 5'teki yeni asenkron işleviyle hemen hemen aynı şey olan asenkron iş akışlarında anahtar kelimeyi kullandığını belirtmek gerekir . Bu nedenle, bunu aynı tutacağım

For awaitF # anahtar kelime, onlar sadece kullanmak let!yerine let. C # aynı atama sözdizimine sahip olmadığından, =işaretin sağ tarafında bir şeye ihtiyaç duyarlar . Benjol'un dediği gibi, yieldneredeyse aynı şekilde çalışır.


1
Bir "beklemenin" bir ödevde olmasına gerek yoktur (elbette tipik olarak olsa da.) GetAwaiter bulabileceğimiz bir türden herhangi bir ifadede operatör olarak yasaldır. (Tam kurallar henüz yayınlanabilir bir formda
Eric Lippert

1
@Eric, F # 'de olurdu do!, ama biliyordun ...
Benjol

1

yield async FetchAsync(..)


Bu async, çağırdığınız yöntemi kullanmanız gereken değiştirici ile mükemmel bir şekilde gider . Ve ayrıca akımın semantiği , numaralandırma koduna yürütmeyi yield returndöndürür ve verirken, bu durumda yürütmeyi eşzamansız yöntemle verirsiniz.

Gelecekte bunun için başka kullanımlar olacaksa yield, yield xx'in aynı şeyi yapmak için tüm bu farklı anahtar kelimelere sahip olmak yerine parlak yeni özellik olduğunu ekleyebiliriz .

Açıkçası, 'infaz sağlamayan' iddiasını tam olarak anlamıyorum. Sonuçta, başka bir yöntemi çağırmanın amacı zaten bu yönteme 'yürütme sağlamak' değil mi? Eşzamansız olup olmadığına bakılmaksızın? Burada bir şey mi eksik?

Ve eğer asynceşzamanlı olarak döndürürse, ancak anahtar kelimeye sahipseniz, yöntemin eşzamansız olarak çalışma olasılığı ve başka bir yönteme yürütme olasılığınız olduğunu belirtmelidir. Yönteminiz, yöntemin gerçekten eşzamansız çağrılar yapıp yapmadığına bakılmaksızın bunu hesaba katmalıdır.

IMO Bence çeşitli 'verimsiz' davalar bir uygulama detayı. Dilde tutarlılık (örneğin yeniden kullanma yield) için kefil olmayı tercih ederim .


0

Nasıl yaklaşık completeolduğu gibi "Ben görevi tamamlandı istiyoruz"?

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

1
Neden inişli çıkışlı? En azından düşüşten sonra kendinizi açıklamak nezakettir.
Allon Güralnek

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.