'Eşzamansız' ve 'bekliyor' nasıl ve ne zaman kullanılır?


1065

Anladığım kadarıyla asyncveawait yapılacak en önemli şeylerden biri, kodun yazılmasını ve okunmasını kolaylaştırmaktır - ancak bunları uzun süreli mantık gerçekleştirmek için arka plan iş parçacıklarına eşittir mi?

Şu anda en temel örneği deniyorum. Satır içi bazı yorumlar ekledim. Benim için açıklığa kavuşturabilir misin?

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}

48
Ayrıca, örnek kodunuzda yukarıdaki kodu derlerken bir uyarı alırsınız. Uyarıyı dikkate alın . Size bu kodun mantıklı olmadığını söylüyor.
Eric Lippert

Yanıtlar:


759

Ne zaman kullanarak asyncveawait derleyici arka planda bir durum makinesi üretir.

İşte devam eden yüksek düzey ayrıntılardan bazılarını açıklayabileceğimi umduğum bir örnek:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

Tamam, burada ne olur:

  1. Task<int> longRunningTask = LongRunningOperationAsync(); yürütmeye başlar LongRunningOperation

  2. Bağımsız İş üzerinde Ana İş Parçasını (İş Parçacığı Kimliği = 1) await longRunningTask ulaşıldı.

    Şimdi, longRunningTaskbitirmediyse ve hala çalışıyorsa, MyMethodAsync()arama yöntemine dönecektir, böylece ana iş parçacığı engellenmez. İşlem longRunningTasktamamlandığında, ThreadPool'daki bir iş parçacığı (herhangi bir iş parçacığı olabilir) MyMethodAsync()önceki bağlamına geri döner ve yürütmeye devam eder (bu durumda sonucu konsola yazdırır).

İkinci bir durum longRunningTask, yürütmeyi zaten bitirmiş olması ve sonucun mevcut olmasıdır. await longRunningTaskBiz ulaştığında zaten sonuç var, böylece kod aynı iş parçacığında yürütmeye devam edecektir. (bu durumda konsola yazdırma sonucu). Tabii ki, söz konusu olan yukarıdaki örnek için durum böyle değildir Task.Delay(1000).


65
Neden "Görev.Gecikme (1000);" LongRunningOperation asenkron yönteminde?
Benison Sam

3
@codea Eric Lippert'in makaleye yaptığı yorumlarında, DoEvents stratejisini async-await ile özellikle karşılaştırdığı bu konuyla ilgili bir giriş makalesi bağlantılandırdı
Camilo Martinez

13
@ BenisonSam iplik biraz eski, ama aynı soru vardı ve bir cevap arıyordum. "Bekliyor" nedeni, "Bekliyor" atlarsak LongRunningOperationAsync () hemen dönecektir. Aslında derleyici, beklemeyi kaldırırsak bir uyarı verecektir. Stephen Cleary'nin blog yazısı blog.stephencleary.com/2011/09/… tasarım tartışmalarının bir göstericisini veriyor.
shelbypereira

70
Her zaman uyumsuz yöntemin içinde bir bekleme beklemesi gerekiyorsa ve bir bekleme yalnızca zaman uyumsuz bir yöntemle yapılabilirse, ne zaman durur?
Bruno Santos

108
Bu cevap açıkça yanlış. Bu çok upvotes birçok kullanıcı için yanlış anlama neden olacaktır. MS belgeleri açıkça, sadece async kullanırken başka bir iş parçacığı kullanılmadığını söylüyor. msdn.microsoft.com/en-us/library/mt674882.aspx Lütfen birileri cevabı düzeltin. Bu yüzden bir gün harcadım.
Krishna Deepak

171

Anladığım kadarıyla, zaman uyumsuz ve beklemekte olan en önemli şeylerden biri, kodun yazılmasını ve okunmasını kolaylaştırmaktır.

Onlar yapmak konum asenkron evet yazma kolay kodu ve okuyun.

Uzun süreli mantık gerçekleştirmek için arka plan iş parçacığı yumurtlama aynı şey midir?

Bir şey değil.

// Bu yöntemin neden 'zaman uyumsuz' olarak işaretlenmesi gerektiğini anlamıyorum.

asyncAnahtar kelime sağlayan awaitanahtar kelimeyi. Bu nedenle, kullanılan herhangi bir yöntem awaitişaretlenmelidir async.

// Bu satıra DoSomethingAsync () yönteminden 5 saniye uykudan sonra ulaşılır. Hemen ulaşılmamalı mı?

Hayır, çünkü asyncyöntemler varsayılan olarak başka bir iş parçacığında çalışmaz.

// Bu bir arka plan iş parçacığında yürütülüyor mu?

Hayır.


async/ awaitİntro'yu yararlı bulabilirsiniz . Resmi MSDN dokümanlar da (özellikle alışılmadık iyi TAP bölümü) ve asyncekibi mükemmel bir söndürüldü SSS .


6
Yani bir arka plan iş parçacığında çalışmıyor, ama aynı zamanda engellemiyor. Bu, iş parçacıklarıyla hokkabazlık yapmak yerine geri arama kullanan eşzamansız API'ler nedeniyle mümkündür. Bir (I / O, soket, ..) işlemi başlatır ve işlerinizi yapmaya geri dönersiniz. İşlem tamamlandığında işletim sistemi geri aramayı başlatır. Node.js veya Python Twisted çerçevesinin yaptığı budur ve onların da güzel açıklamaları vardır.
Roman Plášil

3
Msgstr "Async anahtar sözcüğü await anahtar sözcüğünü etkinleştirir. Bu yüzden, await kullanan herhangi bir yöntem async olarak işaretlenmelidir.", Ama neden? bu cevap, yöntemin neden zaman uyumsuz olarak işaretlenmesi gerektiğini anlamaya yardımcı olmaz. Derleyici, anahtar kelimeleri içini arayarak yöntemin zaman uyumsuz olduğunu çıkaramaz mı?
Stanislav

9
@Stanislav: Bu soruyu ele alan bir blog girişim var .
Stephen Cleary

3
Önerilen açıklama: Hayır, çünkü asyncyöntemler varsayılan olarak başka bir iş parçacığında çalışmaz. Örneğin, içindeki Sleep()çağrı DoSomethingAsync()geçerli iş parçacığını engeller, bu da yürütmenin tamamlanıncaya button1_Click()kadar devam etmesini önler DoSomethingAsync(). Unutmayın ki Thread.Sleep()yürütme iş parçacığını engeller,Task.Delay() does not.
DavidRR

166

açıklama

İşte yüksek düzeyde async/ için hızlı bir örnek await. Bunun ötesinde düşünülmesi gereken çok daha fazla ayrıntı var.

Not: Task.Delay(1000) 1 saniye boyunca iş yapmayı simüle eder. Bence bunu harici bir kaynaktan yanıt beklemek olarak düşünmek en iyisidir. Kodumuz bir yanıt beklediğinden, sistem çalışan görevi bir kenara atabilir ve iş bittikten sonra geri gelebilir. Bu arada, bu iş parçacığı üzerinde başka işler yapabilir.

Aşağıdaki örnekte, ilk blok tam olarak bunu yapıyor. Tüm görevleri hemen başlatır ( Task.Delaysatırlar) ve onları bir kenara bırakır. Kod,await a , sonraki satıra gitmeden önce 1 saniyelik gecikme gerçekleşene kadar satırda . Yana b, c, dve etüm neredeyse tamamen aynı anda yürütülüyor başladı a(nedeniyle beklemektedir eksikliğinden), bunlar bu durumda kabaca aynı zamanda bitirmeliyiz.

Aşağıdaki örnekte, ikinci blok bir görevi awaitbaşlatır ve sonraki görevleri başlatmadan önce bitmesini (yani ne yapar) bekler . Bunun her tekrarı 1 saniye sürer. Programı awaitduraklatıyor ve devam etmeden önce sonucu bekliyor. Birinci ve ikinci bloklar arasındaki ana fark budur.

Misal

Console.WriteLine(DateTime.Now);

// This block takes 1 second to run because all
// 5 tasks are running simultaneously
{
    var a = Task.Delay(1000);
    var b = Task.Delay(1000);
    var c = Task.Delay(1000);
    var d = Task.Delay(1000);
    var e = Task.Delay(1000);

    await a;
    await b;
    await c;
    await d;
    await e;
}

Console.WriteLine(DateTime.Now);

// This block takes 5 seconds to run because each "await"
// pauses the code until the task finishes
{
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
}
Console.WriteLine(DateTime.Now);

ÇIKTI:

5/24/2017 2:22:50 PM
5/24/2017 2:22:51 PM (First block took 1 second)
5/24/2017 2:22:56 PM (Second block took 5 seconds)

SynchronizationContext hakkında ek bilgi

Not: Burası işlerin benim için biraz sisli olduğu yerdir, bu yüzden herhangi bir konuda yanlışsam, lütfen beni düzeltin ve cevabı güncelleyeceğim. Bunun nasıl çalıştığına dair temel bir anlayışa sahip olmanız önemlidir ConfigureAwait(false), ancak optimizasyon için bazı fırsatlardan mahrum kalacağınız sürece, asla kullanmadığınız sürece üzerinde uzman olmadan alabilirsiniz .

Yapar bu bir yönü vardır async/await kavramak kavramı biraz hileli. Bu örnekte, bunların hepsi aynı iş parçacığında (veya en azından onunla ilgili olarak aynı iş parçacığı gibi görünen SynchronizationContext) gerçekleşiyor. Varsayılan olarak,await üzerinde çalıştığı orijinal iş parçacığının eşitleme içeriğini geri yükler. Örneğin, ASP.NET'te HttpContextbir istek geldiğinde bir iş parçacığına bağlı olan bir bağlantınız vardır. Bu bağlam, özgün Http isteğine özgü, dil, IP adresi, başlıklar vb. Bir şeyi işleyerek iş parçacıklarının yarısını değiştirirseniz, potansiyel olarak farklı bir nesnede bu nesneden bilgi almaya çalışabilirsiniz.HttpContextbu felaket olabilir. Bağlamı hiçbir şey için kullanmayacağınızı biliyorsanız, "umursamayı" seçebilirsiniz. Bu temelde, kodunuzun bağlamı beraberinde getirmeden ayrı bir iş parçacığında çalışmasına izin verir.

Bunu nasıl başarıyorsunuz? Varsayılan olarak, await a;kod aslında bağlamı yakalamak ve geri yüklemek istediğinizi varsayar:

await a; //Same as the line below
await a.ConfigureAwait(true);

Ana kodun orijinal bağlam olmadan yeni bir iş parçacığında devam etmesine izin vermek istiyorsanız, bağlam yerine geri yüklenmesi gerekmediğini bilmesi için true yerine false kullanın.

await a.ConfigureAwait(false);

Program duraklatıldıktan sonra, potansiyel olarak tamamen farklı bir iş parçacığında farklı bir bağlamda devam edecektir . Bu, performans iyileştirmenin geldiği yerdir - başladığı orijinal içeriği geri yüklemek zorunda kalmadan mevcut herhangi bir iş parçacığında devam edebilir.

Bu kafa karıştırıcı mı? Cehennem evet! Bunu çözebilir misin? Muhtemelen! Kavramları kavradığınızda, Stephen Cleary'nin teknik anlayışı async/ awaitzaten olan birisine daha fazla yönelik olma eğilimindeki açıklamalarına geçin .


Tüm bu görevin bir int döndürüyor ve ikinci görevin (veya bazı hesaplama) ilk görevin sonucunu kullanıyorsam yanlış olur?
veerendra gupta

3
@veerendragupta evet. Bu durumda bilinçli olarak onları eşzamansız çalıştırmamayı tercih edersiniz (çünkü eşzamansız değildir). Buraya girmeyeceğim yapılandırma bağlamıyla ilgili olarak gerçekleştirilecek birkaç şey daha var
Joe Phillips

Yani await MethodCall()mutlak kaybı mı? Siz de await/ async?
Vitani

2
@Jocie Pek sayılmaz. Aradığınızda await, iş parçacığını tutmak yerine havuza geri bıraktığını düşünüyorum. Bu, Görevin geri dönüşünü beklerken başka bir yerde kullanılabilir hale getirir
Joe Phillips

2
@JoePhillips Sanırım az önce söylediğin şey async / beklemenin özü. Çağıran evre serbest bırakılır ve makinedeki diğer işlemler tarafından kullanılabilir. Bekleme çağrısı tamamlandığında, arayanın ilk başladığını sürdürmek için yeni bir iş parçacığı kullanılır. Arayan hala bekliyor, ancak yararı bu arada bir iş parçacığının serbest bırakılmış olmasıdır. Bu asenkron / beklemenin yararı mı?
Bob Horn

147

Diğer cevaplara ek olarak, bir göz atın (C # Referans)

ve daha spesifik olarak dahil edilen örnekte durumunuzu biraz açıklıyor

Aşağıdaki Windows Forms örneği, bir async yönteminde WaitAsynchronouslyAsync yönteminde await komutunun kullanımını gösterir. Bu yöntemin davranışını WaitSynchronously davranışı ile karşılaştırın. Bir göreve bekleyen bir operatör olmadan, tanımında async değiştiricisinin kullanılmasına ve kendi iş parçacığında Thread.Sleep çağrısına rağmen WaitSynchronously senkronize olarak çalışır.

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}

3
Cevap için teşekkürler. Ancak WaitAsynchronouslyAsync () ayrı bir iş parçacığında yürütülür mü?
Dan Dinu

32
Ben inanıyorum, bölümünden Bekleyen bir ifade üzerinde çalıştığı iş parçacığını engellemez. Bunun yerine, derleyicinin async yönteminin geri kalanını beklenen görevde bir devamı olarak kaydetmesine neden olur. Denetim daha sonra zaman uyumsuz yöntemin arayanına geri döner. Görev tamamlandığında, devam etmesini başlatır ve zaman uyumsuz yöntemin yürütülmesi kaldığı yerden devam eder.
Adriaan Stander

13
Göre bu MSDN makalesinde , "zaman uyumsuz ve bekliyoruz anahtar kelimeler bir zaman uyumsuz yöntem kendi iş parçacığı üzerinde çalışmaz .... ek iş parçacığı oluşturulamaz neden olmaz". Anladığım kadarıyla, uzun işlemlerin bitmesini beklerken tüm olası bağımsız kodların çalışmasına izin vermek için anahtar kelimeler beklenirken çerçeve ileriye (arayana geri) atlar. Bu, tüm bağımsız kod çalıştırıldığında, uzun işlem geri dönmezse, bloke olacağı anlamına gelir. Bunu şimdi öğreniyorum.
Vimes

9
@astander Bu yanlış. O mu değil farklı bir iş parçacığı üzerinde yürütmek. Sadece zamanlayıcı Task.Delayyangınlar tarafından kullanıldığında çağrının (yöntemin geri kalanı) zamanlanmasını sağlar .
MgSam

1
Bu cevap Uyku yüzünden yanlış. Bekleyen Görev ile ilgili cevaba bakınız. Gecikme (1000); doğru davranışa sahip.
Jared Updike

62

Yukarıdaki açıklamaları basit bir konsol programında çalışırken gösterme:

class Program
{
    static void Main(string[] args)
    {
        TestAsyncAwaitMethods();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }

    public async static void TestAsyncAwaitMethods()
    {
        await LongRunningMethod();
    }

    public static async Task<int> LongRunningMethod()
    {
        Console.WriteLine("Starting Long Running method...");
        await Task.Delay(5000);
        Console.WriteLine("End Long Running method...");
        return 1;
    }
}

Ve çıktı:

Starting Long Running method...
Press any key to exit...
End Long Running method...

Böylece,

  1. Main, uzun süre çalışarak yöntemi başlatır TestAsyncAwaitMethods. Bu, geçerli iş parçacığını durdurmadan hemen geri döner ve hemen 'Çıkmak için herhangi bir tuşa basın' iletisini görürüz
  2. Tüm bu süre LongRunningMethodboyunca, arka planda çalışıyor. Tamamlandığında, Threadpool'dan başka bir iş parçacığı bu bağlamı alır ve son mesajı görüntüler

Böylece, iplik değil engellenir.


"Çıkmak için herhangi bir tuşa basın ..." çıkışın hangi bölümünde gösterilecek?
StudioX

1
ve (dönüş 1) ne işe yarar? bu gerekli mi?
StudioX

1
@StudioX dönüş tipi tamsayı olması gerektiğini düşünüyorum
Kuba Do

Bence return 1bölüm daha fazla açıklamayı hak ediyor: awaitanahtar kelime Task<T>doğrudan altta yatan türü döndürmenize izin verir , böylece mevcut kodunuzu bekleyen / zaman uyumsuz dünyaya uyarlamanızı kolaylaştırır . Ancak , bir değer döndürmek zorunda değilsiniz , çünkü geri Taskdönen bir tür belirtmeden bir eşzamanlı voidyöntemin eşdeğeri olan bir döndürmek mümkündür . C # async voidyöntemlerine izin verir , ancak olay işleyicileri mücadele sürece bunu yapmaktan kaçınmalısınız.
Christiano Kiss

41

Bence kötü bir örnek seçtiniz System.Threading.Thread.Sleep

Bir Point asyncGörev böyle a yapıyor gibi ana iş parçacığı kilitlemeden arka planda yürütmek izin vermektirDownloadFileAsync

System.Threading.Thread.Sleep "yapılan" bir şey değil, sadece uyuyor ve bu nedenle bir sonraki satıra 5 saniye sonra ulaşılıyor ...

Bu makaleyi okuyun, bunun harika bir açıklaması asyncve awaitkonsepti olduğunu düşünüyorum : http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx


3
Uyku neden kötü bir örnek ama İndir iyi bir örnek. Ben Thread.Sleep zaman alır bazı görev olduğunu anlıyorum gördüğüm zaman FooBar bir şey gibi. Sanırım sorusu alakalı
Abdurrahim

1
@Abdurrahim Thread.Sleepiş parçacığını engeller (iş parçacığı boşta oturmak dışında başka bir şey yapamaz), ancak zaman uyumsuz bir yöntem yapmaz. Durumda DownloadFileAsync, iş parçacığı uzak sunucudan bir yanıt gelene kadar başka bir şey yapabilir. Bir zaman uyumsuz yöntemde "zaman alan bazı görevler" için daha iyi bir yer tutucudur Task.Delay, çünkü bu aslında zaman uyumsuzdur.
Gabriel Luci

@ GabrielLuci itirazım Gecikme vs Uyku ile ilgili değil; Cevabınız daha çok bir strawman cevabı gibi görünüyor; Eğer itiraz edemeyeceğim bir soruya bunu bir yorum olarak koyarsanız, ama bir cevap olarak daha çok bir strawman cevabı gibi kokuyor. Bence o yapmak zorunda olduğu tüm çağrıları bile engelleme olacak zaman uyumsuz kullanmak için iyi olduğunu düşünüyorum; Tüm amacı geçersiz kılmayacak ... Geriye kalan tek şey bile geçerli bir durum olarak saydığı sözdizimsel şeker olacak,
Abdurrahim

1
Bu benim cevabım değildi. Ancak amacınıza hitap etmek için: yöntemin amacına bağlıdır. Sadece aramak için bir yöntem isterse başarılı oldu. Fakat bu durumda eşzamansız çalışan bir yöntem yapmaya çalışıyordu. Bunu sadece asyncanahtar kelimeyi kullanarak yaptı . Ancak yöntemi hala eşzamanlı olarak koştu ve bu cevap nedenini mükemmel bir şekilde açıkladı: çünkü aslında herhangi bir eşzamansız kod çalıştırmadı. Tamamlanmamış asyncolana kadar işaretlenen yöntemler eşzamanlı olarak çalışır . Hayır yoksa , yöntem eşzamanlı olarak çalışır ve derleyici sizi bu konuda uyarır. awaitTaskawait
Gabriel Luci

23

İşte takip edenlere açıklık getirmek için hızlı bir konsol programı. TaskToDoYöntem zaman uyumsuz yapmak istiyorum ki uzun koşu yöntemidir. Zaman uyumsuz çalışmasını sağlamak TestAsyncyöntemi ile yapılır . Test döngüleri yöntemi yalnızca TaskToDogörevler boyunca çalışır ve bunları zaman uyumsuz olarak çalıştırır. Sonuçlarda, çalışmadan çalışmaya aynı sırada tamamlanmadığı için bunu görebilirsiniz - tamamlandığında konsol UI iş parçacığına rapor veriyorlar. Basit, ancak bence basit örnekler modelin çekirdeğini daha fazla örneklerden daha iyi ortaya koyuyor:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestingAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoops();
            Console.Read();
        }

        private static async void TestLoops()
        {
            for (int i = 0; i < 100; i++)
            {
                await TestAsync(i);
            }
        }

        private static Task TestAsync(int i)
        {
            return Task.Run(() => TaskToDo(i));
        }

        private async static void TaskToDo(int i)
        {
            await Task.Delay(10);
            Console.WriteLine(i);
        }
    }
}

20

En hızlı öğrenme için ..

  • Yöntem yürütme akışını anlama (şema ile): 3 dakika

  • Soru özeleştirme (öğrenme uğruna): 1 dk

  • Sözdizimi şekeri hızlıca alın: 5 dakika

  • Bir geliştiricinin karışıklığını paylaşın: 5 dakika

  • Sorun: Normal kodun gerçek dünyadaki bir uygulamasını Async koduna hızla değiştirin: 2 dakika

  • Nerede Sonraki?

Yöntem yürütme akışını anlama (şema ile): 3 dakika

Bu resimde sadece # 6'ya odaklanın (başka bir şey yok) resim açıklamasını buraya girin

6. adımda: İş bittiği için uygulama burada durdu. Devam etmek için getStringTask (bir tür işlev) sonucuna ihtiyaç var. Bu nedenle, awaitilerlemesini askıya almak ve arayan kişiye (içinde bulunduğumuz bu yöntemin) kontrolü (verim) vermek için bir operatör kullanır . GetStringTask için gerçek çağrı # 2'nin başlarında yapıldı. # 2'de bir dize sonucu döndürmek için bir söz verildi. Ama sonucu ne zaman döndürecek? (# 1: AccessTheWebAsync) tekrar 2. bir çağrı yapmalı mıyız? Sonucu kim alır, # 2 (çağrı bildirimi) veya # 6 (bekleyen ifade)

AccessTheWebAsync () harici arayan da şimdi bekliyor. Bu yüzden arayan AccessTheWebAsync bekliyor ve AccessTheWebAsync şu anda GetStringAsync bekliyor. İlginç olan şey AccessTheWebAsync beklemeden önce biraz çalışma yaptı (# 4) belki de bekleme zamanından tasarruf etmek için. Harici görevli (ve zincirdeki tüm arayanlar) için aynı anda çoklu görev yapma özgürlüğü de mevcuttur ve bu 'asenkron' şeyin en büyük artısıdır! Eşzamanlı gibi hissediyorsunuz ... ya da normal ama değil.

Unutmayın, yöntem zaten iade edildi (# 2), tekrar geri dönemez (ikinci kez yok). Peki arayan kişi nasıl bilecek? Her şey Görevlerle ilgili! Görev kabul edildi. Görev beklendi (yöntem değil, değer değil). Değer Görev'de ayarlanır. Görev durumu tamamlanacak şekilde ayarlanacak. Arayan sadece Görev (# 6) 'yı izler. Yani 6 # sonucu nereden / kimin alacağının cevabıdır. Daha sonra okumak için burada .

Soru aşkına iç gözlem: 1 dk

Soruyu biraz ayarlayalım:

Nasıl ve ne zaman kullanılır? Ve ? asyncawait Tasks

Çünkü öğrenme Taskotomatik olarak diğer ikisini kapsar (ve sorunuzu cevaplar)

Sözdizimi şekeri hızlıca alın: 5 dakika

  • Dönüştürmeden önce (orijinal yöntem)

    internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }

  • Yukarıdaki yöntemi çağırmak için Görev-ified yöntemi

    internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }

Bekliyor muyuz yoksa zaman uyumsuz mu? Hayır. Yukarıdaki yöntemi çağırın ve izleyebileceğiniz bir görev alırsınız. Görevin ne döndürdüğünü zaten biliyorsunuz .. bir tamsayı.

  • Bir Görevi çağırmak biraz zor ve o zaman anahtar kelimeler görünmeye başlar. MethodTask () öğesini çağıralım

    internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }

Yukarıdaki aynı kod aşağıdaki resim olarak eklendi: resim açıklamasını buraya girin

  1. İşin bitmesini 'bekliyoruz'. Dolayısıylaawait
  2. Bekliyoruz, kullanmalıyız async(zorunlu sözdizimi)
  3. Ön Asyncek olarak MethodAsync (kodlama standardı)

awaitanlaşılması kolaydır, ancak kalan iki ( async, Async) :) olmayabilir. Eh, sonrası için okur though.Further derleyiciye bir çok daha mantıklı olmalıdır burada

Yani 2 bölüm var.

  1. 'Görev' oluştur
  2. Görevi çağırmak için sözdizimsel şeker oluşturun ( await+async)

Unutmayın, AccessTheWebAsync () için harici bir arayanımız vardı ve bu arayan da korunmuyor ... yani aynı ihtiyacı var await+async. Ve zincir devam ediyor. Ama her zaman Taskbir ucunda bir olacak.

Tamam, ama bir geliştirici # 1'in (Görev) eksik olduğunu görünce şaşırdı ...

Bir geliştiricinin karışıklığını paylaşın: 5 dakika

Bir geliştirici uygulama yapmama hatası yaptı Taskama hala çalışıyor! Soruyu ve burada verilen kabul edilen cevabı anlamaya çalışın . Umarım okudunuz ve tamamen anladınız. Özet 'Görev'i göremeyebileceğimiz / uygulayamayacağımız, ancak üst sınıfta bir yerde uygulandığımızdır. Benzer şekilde, zaten inşa edilmiş bir örneği çağırmak MethodAsync(), bu yöntemi Task( MethodTask()) kendimizle uygulamaktan çok daha kolaydır . Çoğu geliştirici, Tasksbir kodu Eşzamansız olana dönüştürürken başını bulmakta zorlanır .

İpucu: Zorluğu dışa aktarmak için mevcut bir Async uygulamasını ( MethodAsyncveya gibi ToListAsync) bulmaya çalışın . Bu yüzden sadece Async ile uğraşmamız ve beklememiz gerekiyor (bu kolay ve normal koda oldukça benzer)

Sorun: Normal kodun gerçek dünyadaki uygulamasını Async işlemine hızlıca değiştirin: 2 dakika

Veri Katmanı'nda aşağıda gösterilen kod satırı kesilmeye başlandı (birçok yer). Çünkü bazı kodlarımızı .Net framework 4.2. * 'Dan .Net core' a güncelledik. Biz uygulamanın her yerinde 1 saat içinde düzeltmek zorunda kaldı!

var myContract = query.Where(c => c.ContractID == _contractID).First();

çantada keklik!

  1. EnteryaFramework nuget paketini QueryableExtensions olduğundan kurduk. Ya da başka bir deyişle, Async uygulamasını (görev) yapar, böylece basit Asyncve awaitkodla hayatta kalabiliriz .
  2. namespace = Microsoft.EntityFrameworkCore

çağıran kod satırı böyle değişti

var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
  1. Yöntem imzası değiştirildi

    Contract GetContract(int contractnumber)

    için

    async Task<Contract> GetContractAsync(int contractnumber)

  2. çağrı yöntemi de etkilendi: GetContractAsync(123456);olarak adlandırıldıGetContractAsync(123456).Result;

  3. Biz her yerde 30 dakika içinde değişti!

Ancak mimar bize EntityFramework kütüphanesini bunun için kullanmamamızı söyledi! ayy! dram! Sonra özel bir Görev uygulaması yaptık (yuk). Hangisini biliyorsun. Hala kolay! ..still yuk ..

Nerede Sonraki? ASP.Net Core'da Senkronize Çağrıları Asenkronize Dönüştürme hakkında izleyebileceğimiz harika bir hızlı video var , belki de bu muhtemelen bunu okuduktan sonra gidecek yön.


harika cevap! Bu bana bir ton yardımcı oldu
cklimowski

1
Güzel cevap. Sadece birkaç küçük şeyi düzeltmek isteyebilirsiniz: (a) ".Net framework 4.2" (bildiğim böyle bir sürüm yok) söz konusu (b) EntityFrameWork => EntityFramework
immitev

15

Buradaki tüm cevaplar Task.Delay()veya başka bir yerleşik asyncişlev kullanır. Ama işte bu asyncişlevlerin hiçbirini kullanmayan örneğim :

// Starts counting to a large number and then immediately displays message "I'm counting...". 
// Then it waits for task to finish and displays "finished, press any key".
static void asyncTest ()
{
    Console.WriteLine("Started asyncTest()");
    Task<long> task = asyncTest_count();
    Console.WriteLine("Started counting, please wait...");
    task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
    //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
    Console.WriteLine("Finished counting.");
    Console.WriteLine("Press any key to exit program.");
    Console.ReadLine();
}

static async Task<long> asyncTest_count()
{
    long k = 0;
    Console.WriteLine("Started asyncTest_count()");
    await Task.Run(() =>
    {
        long countTo = 100000000;
        int prevPercentDone = -1;
        for (long i = 0; i <= countTo; i++)
        {
            int percentDone = (int)(100 * (i / (double)countTo));
            if (percentDone != prevPercentDone)
            {
                prevPercentDone = percentDone;
                Console.Write(percentDone.ToString() + "% ");
            }

            k = i;
        }
    });
    Console.WriteLine("");
    Console.WriteLine("Finished asyncTest_count()");
    return k;
}

2
Teşekkür ederim! ilk cevap beklemek yerine biraz işe yarıyor.
Jeffnl

task.Wait();ve async / cehennemden kaçınmak için nasıl kullanıldığını gösterdiğiniz için teşekkür ederiz : P
kodlayıcı

12

Bu yanıt ASP.NET'e özgü bazı bilgiler sağlamayı amaçlamaktadır.

MVC kontrol cihazında zaman uyumsuz / beklemeden yararlanarak, aşağıdaki makalede açıklandığı gibi, iş parçacığı havuzu kullanımını artırmak ve çok daha iyi bir iş hacmi elde etmek mümkündür,

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

Başlangıçta çok sayıda eşzamanlı istek gören veya çoğuşan yüke sahip (eşzamanlılığın aniden arttığı) web uygulamalarında, bu web hizmeti çağrılarını eşzamansız hale getirmek uygulamanızın yanıt verebilirliğini artıracaktır. Eşzamansız bir isteğin, eşzamanlı bir isteğin işlenmesi aynı zaman alır. Örneğin, bir istek tamamlanması iki saniye gerektiren bir web hizmeti çağrısı yaparsa, isteğin eşzamanlı veya eşzamansız olarak gerçekleştirilmesi iki saniye sürer. Ancak, eşzamansız bir çağrı sırasında, bir iş parçacığının, ilk isteğin tamamlanmasını beklerken diğer isteklere yanıt vermesi engellenmez. Bu nedenle, uzun süre çalışan işlemleri başlatan birçok eşzamanlı istek olduğunda, zaman uyumsuz istekler istek kuyruğunu ve iş parçacığı havuzu büyümesini engeller.


12

Zaman uyumsuzluk ve basit açıklama beklemek

Basit Analoji

Bir kişi sabah trenini bekleyebilir . Yaptıkları tek şey bu, çünkü şu anda gerçekleştirdikleri birincil görev. (senkron programlama (normalde yaptığınız şey!))

Bir başka kişi sigara içerken sabah kahvesini beklerken kahvesini içebilir. (Zaman uyumsuz programlama)

Eşzamansız programlama nedir?

Zaman uyumsuz programlama, bir programcının kodunun bir kısmını ana yürütme iş parçacığından ayrı bir iş parçacığında çalıştırmayı ve ardından ana iş parçacığını tamamlandığında bilgilendirmeyi seçeceği yerdir.

Async anahtar sözcüğü gerçekte ne yapar?

Eşzamansız anahtar sözcüğe,

async void DoSomething(){ . . .

zamanlayıcının zaman uyumsuz görevleri çağırırken await anahtar sözcüğünü kullanmasına izin verir. Tüm yaptığı bu.

Bu neden önemli?

Birçok yazılım sisteminde ana iş parçacığı, özellikle Kullanıcı Arayüzü ile ilgili işlemler için ayrılmıştır. Bilgisayarımda tamamlanması 5 saniye süren çok karmaşık bir özyinelemeli algoritma çalıştırıyorsam, ancak bunu Ana Konu (UI iş parçacığı) üzerinde çalıştırıyorum Kullanıcı uygulamamdaki herhangi bir şeye tıklamaya çalıştığında, donmuş gibi görünecek benim ana iş parçacığı sıraya ve şu anda çok fazla işlem yapıyor gibi. Sonuç olarak, ana iş parçacığı düğmeyi tıklama yöntemini çalıştırmak için fare tıklaması işleyemiyor.

Async ve Await'i ne zaman kullanıyorsunuz?

Kullanıcı arayüzünü içermeyen bir şey yaparken asenkron anahtar kelimeleri ideal olarak kullanın.

Diyelim ki kullanıcının cep telefonunda çizim yapmasına izin veren bir program yazıyorsunuz ama her 5 saniyede bir internette hava durumunu kontrol ediyor olacak.

Uygulama kullanıcısının güzel resimler çekmek için mobil dokunmatik ekranla etkileşime girmeye devam etmesi gerektiğinden, hava durumunu almak için her 5 saniyede bir anket çağrısını beklemeliyiz.

Async ve Await'i nasıl kullanıyorsunuz?

Yukarıdaki örnekten sonra, nasıl yazıldığına dair bazı sahte kodlar:

    //ASYNCHRONOUS
    //this is called using the await keyword every 5 seconds from a polling timer or something.

    async Task CheckWeather()
    {
        var weather = await GetWeather();
        //do something with the weather now you have it
    }

    async Task<WeatherResult> GetWeather()
    {

        var weatherJson = await CallToNetworkAddressToGetWeather();
        return deserializeJson<weatherJson>(weatherJson);
    }

    //SYNCHRONOUS
    //This method is called whenever the screen is pressed
    void ScreenPressed()
    {
        DrawSketchOnScreen();
    }

Ek Notlar - Güncelleme

Orijinal notlarımda C # 'da yalnızca Görevler'e sarılmış yöntemleri bekleyebileceğinizi söylemeyi unuttum. örneğin bu yöntemi bekleyebilirsiniz:

// awaiting this will return a string.
// calling this without await (synchronously) will result in a Task<string> object.
async Task<string> FetchHelloWorld() {..

Bunun gibi görev olmayan yöntemleri bekleyemezsiniz:

async string FetchHelloWorld() {..

Görev sınıfının kaynak kodunu buradan inceleyebilirsiniz .


4
Bunu yazmak için zaman ayırdığınız için teşekkür ederiz.
Prashant

10

Async / Bekliyor

Aslında Async / Await, eşzamansız bir görevin geri aramasını oluşturmak için sözdizimsel şeker olan bir çift anahtar kelime.

Örnek olarak bu işlemi ele alalım:

    public static void DoSomeWork()
    {
        var task = Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS NOT bubbling up due to the different threads
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // This is the callback
        task.ContinueWith((t) => {
            // -> Exception is swallowed silently
            Console.WriteLine("Completed");

            // [RUNS ON WORKER THREAD]
        });
    }

Yukarıdaki kodun bazı dezavantajları vardır. Hatalar iletilmez ve okunması zordur. Ama Async ve Await bize yardım etmek için geliyorlar:

    public async static void DoSomeWork()
    {
        var result = await Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS bubbling up
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // every thing below is a callback 
        // (including the calling methods)

        Console.WriteLine("Completed");

    }

Bekleyen çağrılar Async yöntemlerinde olmalıdır. Bunun bazı avantajları vardır:

  • Görevin sonucunu döndürür
  • otomatik olarak bir geri arama oluşturur
  • hataları kontrol eder ve çağrı kaydında kabarmalarını sağlar (yalnızca çağrı kaydında hiçbiri beklemeden arama)
  • sonucu bekler
  • ana ipliği serbest bırakır
  • ana iş parçacığında geri arama yapar
  • iş için iş parçacığı havuzundan bir alt iş parçacığı kullanır
  • kodu okumayı kolaylaştırır
  • ve çok daha fazlası

NOT : uyumsuz ve bekliyoruz kullanılır ile uyumsuz çağrı değil Bunları yapmak için. Bunun için Task.Run () gibi Task Libary kullanmanız gerekir .

Bekleyen ve hiçbiri bekleyen çözümler arasında bir karşılaştırma

Bu hiçbiri zaman uyumsuz çözümdür:

    public static long DoTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]
        var task = Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // goes directly further
        // WITHOUT waiting until the task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 50 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Bu, zaman uyumsuz yöntemdir:

    public async static Task<long> DoAwaitTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]

        await Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // Waits until task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 2050 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

Aslında aynat yöntemini await anahtar sözcüğü olmadan çağırabilirsiniz, ancak buradaki herhangi bir İstisna'nın yayın modunda yutulduğu anlamına gelir:

    public static Stopwatch stopWatch { get; } = new Stopwatch();

    static void Main(string[] args)
    {
        Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
        // 2050 (2000 more because of the await)
        Console.WriteLine("DoTask: " + DoTask() + " ms");
        // 50
        Console.ReadKey();
    }

Async ve Await paralel hesaplama için tasarlanmamıştır. Ana ipliğinizi engellememek için kullanılırlar. Asp.net veya Windows uygulamaları ile ilgili olduğunda, bir ağ çağrısı nedeniyle ana iş parçacığınızı engellemek kötü bir şeydir. Bunu yaparsanız, uygulamanız yanıt vermeyecek hatta kilitlenecektir.

Daha fazla örnek için ms docs'a göz atın .


9

Dürüst olmak gerekirse, hala en iyi açıklamanın Wikipedia hakkında gelecek ve vaatlerle ilgili olduğunu düşünüyorum: http://en.wikipedia.org/wiki/Futures_and_promises

Temel fikir, görevleri eşzamansız olarak yürüten ayrı bir iş parçacığı havuzunuz olmasıdır. Kullanırken. Ancak nesne, bir süre için işlemi gerçekleştireceği sözünü verir ve talep ettiğinizde size sonuç verir. Bu, sonucu istediğinizde ve bitirmediğinde engelleneceği, ancak iş parçacığı havuzunda aksi takdirde yürütüleceği anlamına gelir.

Oradan bir şeyleri optimize edebilirsiniz: bazı işlemler zaman uyumsuz olarak uygulanabilir ve sonraki istekleri bir araya getirip / veya yeniden sıralayarak dosya GÇ ve ağ iletişimi gibi şeyleri optimize edebilirsiniz. Bunun zaten Microsoft'un görev çerçevesinde olup olmadığından emin değilim - ancak değilse, ekleyeceğim ilk şeylerden biri olurdu.

Aslında gelecekteki desen sıralama C # 4.0 verimler ile uygulayabilirsiniz. Tam olarak nasıl çalıştığını bilmek istiyorsanız, iyi bir iş yapan bu bağlantıyı önerebilirim: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/ . Bununla birlikte, kendinizle oynamaya başlarsanız, tüm harika şeyleri yapmak istiyorsanız gerçekten dil desteğine ihtiyacınız olduğunu fark edeceksiniz - ki bu tam olarak Microsoft'un yaptığı şeydir.


8

Task, Task.WaitAll (), async ve await kullanımını gösteren basit bir konsol uygulaması çalıştırmak için bu keman https://dotnetfiddle.net/VhZdLU (ve mümkünse geliştirin) için bakın.Aynı programda operatörlerin .

Bu keman, yürütme döngüsü konseptinizi temizlemelidir.

İşte örnek kod

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {               
        var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
        Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
        Console.WriteLine("Now Waiting for Task to be Finished");       
        Task.WaitAll(a); //Now Waiting      
        Console.WriteLine("Exiting CommandLine");       
    }

    public static async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperation();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
        Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine("Result of LongRunningOperation() is " + result);
    }

    public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        Console.WriteLine("LongRunningOperation() Started");
        await Task.Delay(2000); // 2 second delay
        Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
        return 1;
    }   

}

Çıktı Penceresinden gelen izleme: resim açıklamasını buraya girin


3
public static void Main(string[] args)
{
    string result = DownloadContentAsync().Result;
    Console.ReadKey();
}

// You use the async keyword to mark a method for asynchronous operations.
// The "async" modifier simply starts synchronously the current thread. 
// What it does is enable the method to be split into multiple pieces.
// The boundaries of these pieces are marked with the await keyword.
public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
{
    using (HttpClient client = new HttpClient())
    {
        // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
        // If it is already finished, the method continues to run synchronously.
        // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.


        // Http request example. 
        // (In this example I can set the milliseconds after "sleep=")
        String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");

        Console.WriteLine(result);

        // After completing the result response, the state machine will continue to synchronously execute the other processes.


        return result;
    }
}

3

Daha yüksek bir seviyede:

1) Async anahtar sözcüğü sizi bekliyor ve bu kadar. Async anahtar sözcüğü yöntemi ayrı bir iş parçacığında çalıştırmaz. Başlangıç ​​f zaman uyumsuzlama yöntemi, isabetli bir görev için beklemeyinceye kadar senkronize olarak çalışır.

2) T türünün Görev veya Görevini döndüren bir yöntemi bekleyebilirsiniz. Zaman uyumsuz void yönteminde bekleyemezsiniz.

3) Ana iş parçacığıyla karşılaştığı an, zaman alan bir görevde beklenir veya gerçek iş başlatıldığında, ana iş parçacığı geçerli yöntemin arayanına geri döner.

4) Ana iş parçacığı hala yürütülmekte olan bir görev için beklerse, beklemez ve geçerli yöntemin arayanına geri döner. Bu şekilde uygulama yanıt verir.

5) İşlenmeyi bekle, şimdi iş parçacığı havuzundan ayrı bir iş parçacığında yürütülecek.

6) Bu bekleme görevi tamamlandığında, altındaki tüm kod ayrı bir iş parçacığı tarafından yürütülür

Örnek kod aşağıdadır. Yürütün ve evre kimliğini kontrol edin

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncAwaitDemo
{
    class Program
    {
        public static async void AsynchronousOperation()
        {
            Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            //Task<int> _task = AsyncMethod();
            int count = await AsyncMethod();

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            //int count = await _task;

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            DependentMethod(count);

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static async Task<int> AsyncMethod()
        {
            Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            int count = 0;

            await Task.Run(() =>
            {
                Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(20000);
                count = 10;
            });

            Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            return count;
        }       

        public static void DependentMethod(int count)
        {
            Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            AsynchronousOperation();

            Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            Console.ReadKey();
        }

    }
}

2

Anladığım kadarıyla karışımına ilave üçüncü bir terim olmalı, aynı zamanda: Task.

Async yalnızca, eşzamansız bir yöntem olduğunu söylemek için yönteminize koyduğunuz bir niteleyicidir.

Taskasyncfonksiyonun geri dönüşüdür. Zaman uyumsuz olarak yürütülür.

Sen awaitbir görevsin. Kod yürütme bu satıra ulaştığında, kontrol çevrenizdeki orijinal fonksiyonun arayanına geri döner.

Bunun yerine, bir dönüşünü atamak asyncfonksiyonu (yani Taskkod yürütme bu hat ulaştığında, bu sadece bir değişkene kadar) devam çevreleyen işlevindeki bu çizginin geçmiş ikenTask yürütür uyumsuz.


1

süreli mantık gerçekleştirmek için bunları arka plan iş parçacıklarına eşit mi kullanıyorsunuz?

Bu makalede MDSN: Eşzamansız ve beklemede (C #) Eşzamansız Programlama açıkça açıklar:

Zaman uyumsuz ve beklenen anahtar kelimeler ek iş parçacıklarının oluşturulmasına neden olmaz. Eşzamansız yöntemler kendi iş parçacığında çalışmadığından, eşzamansız yöntemler çoklu iş parçacığı gerektirmez. Yöntem geçerli eşitleme bağlamında çalışır ve iş parçacığındaki zamanı yalnızca yöntem etkin olduğunda kullanır.


1

Aşağıdaki kodda, GetByteArrayAsync HttpClient yöntemi bir Görev, getContentsTask döndürür. Görev, görev tamamlandığında gerçek bayt dizisini üretme sözüdür. Await operatörü, getContentsTask tamamlanana kadar SumPageSizesAsync uygulamasında yürütmeyi askıya almak için getContentsTask öğesine uygulanır. Bu arada, kontrol SumPageSizesAsync çağrısına döndürülür. GetContentsTask tamamlandığında, bekleyen ifade bir bayt dizisi olarak değerlendirilir.

private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a 
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}

1

Aşağıda, iletişim kutusunu açarak excel dosyasını okuyan ve ardından async kullanan ve excel'den tek tek satır okuyan ve ızgaraya bağlanan kodu asenkron olarak çalıştırmak için bekleyen kod aşağıdadır

namespace EmailBillingRates
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            lblProcessing.Text = "";
        }

        private async void btnReadExcel_Click(object sender, EventArgs e)
        {
            string filename = OpenFileDialog();

            Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
            Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename);
            Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
            Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
            try
            {
                Task<int> longRunningTask = BindGrid(xlRange);
                int result = await longRunningTask;

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                //cleanup  
               // GC.Collect();
                //GC.WaitForPendingFinalizers();

                //rule of thumb for releasing com objects:  
                //  never use two dots, all COM objects must be referenced and released individually  
                //  ex: [somthing].[something].[something] is bad  

                //release com objects to fully kill excel process from running in the background  
                Marshal.ReleaseComObject(xlRange);
                Marshal.ReleaseComObject(xlWorksheet);

                //close and release  
                xlWorkbook.Close();
                Marshal.ReleaseComObject(xlWorkbook);

                //quit and release  
                xlApp.Quit();
                Marshal.ReleaseComObject(xlApp);
            }

        }

        private void btnSendEmail_Click(object sender, EventArgs e)
        {

        }

        private string OpenFileDialog()
        {
            string filename = "";
            OpenFileDialog fdlg = new OpenFileDialog();
            fdlg.Title = "Excel File Dialog";
            fdlg.InitialDirectory = @"c:\";
            fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
            fdlg.FilterIndex = 2;
            fdlg.RestoreDirectory = true;
            if (fdlg.ShowDialog() == DialogResult.OK)
            {
                filename = fdlg.FileName;
            }
            return filename;
        }

        private async Task<int> BindGrid(Microsoft.Office.Interop.Excel.Range xlRange)
        {
            lblProcessing.Text = "Processing File.. Please wait";
            int rowCount = xlRange.Rows.Count;
            int colCount = xlRange.Columns.Count;

            // dt.Column = colCount;  
            dataGridView1.ColumnCount = colCount;
            dataGridView1.RowCount = rowCount;

            for (int i = 1; i <= rowCount; i++)
            {
                for (int j = 1; j <= colCount; j++)
                {
                    //write the value to the Grid  
                    if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null)
                    {
                         await Task.Delay(1);
                         dataGridView1.Rows[i - 1].Cells[j - 1].Value =  xlRange.Cells[i, j].Value2.ToString();
                    }

                }
            }
            lblProcessing.Text = "";
            return 0;
        }
    }

    internal class async
    {
    }
}

0

Buradaki cevaplar, bekleme / zaman uyumsuzluk hakkında genel bir rehber olarak faydalıdır. Ayrıca, async'in nasıl beklendiği hakkında bazı ayrıntılar içerir. Bu tasarım desenini kullanmadan önce bilmeniz gereken bazı pratik deneyimleri sizinle paylaşmak istiyorum.

"Bekliyor" terimi değişmezdir. Bu nedenle, onu çağırdığınız her ne iş parçacığı devam etmeden önce yöntemin sonucunu bekleyecektir. Açık ön plan iş parçacığı, bu bir felaket . Ön plan iş parçacığı, görünümler, görünüm modelleri, ilk animasyonlar ve bu öğelerle önyükleme yaptığınız diğer şeyler de dahil olmak üzere uygulamanızı oluşturma yükünü taşır. Ön plan iş parçacığını beklediğinizde , uygulamayı durdurun . Kullanıcı hiçbir şey görünmediğinde bekler ve bekler. Bu olumsuz bir kullanıcı deneyimi sağlar.

Kesinlikle çeşitli araçlar kullanarak bir arka plan iş parçacığı bekleyebilirsiniz:

Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });

// Notice that we do not await the following call, 
// as that would tie it to the foreground thread.
try
{
Task.Run(async () => { await AnyAwaitableMethod(); });
}
catch
{}

Bu açıklamalar için tam kod https://github.com/marcusts/xamarin-forms-annoyances adresindedir . AwaitAsyncAntipattern.sln adlı çözüme bakın.

GitHub sitesi de bu konuyla ilgili daha ayrıntılı bir tartışmaya bağlantılar sunar.


1
Anladığım kadarıyla, async / awaitgeri aramalar için sözdizimsel şeker, diş açma ile ilgisi yok. msdn.microsoft.com/tr-tr/magazine/hh456401.aspx CPU'ya bağlı olmayan kod içindir, örn. giriş beklemek veya gecikme. Task.Runyalnızca CPU'ya bağlı kod için kullanılmalıdır blog.stephencleary.com/2013/10/…
geometrikal

The term "await" is literal, so whatever thread you call it on will wait for the result of the method before continuing.Bu doğru değil - belki Task.Wait () demek istediniz? Kullandığınız zaman await, yöntemin geri kalanını, beklediğiniz her şey tamamlandığında yürütülecek bir devam olarak ayarlar. Kullandığınız yöntemden çıkar, böylece arayan devam edebilir. Ardından, beklenen çizgi gerçekten tamamlandığında, bu yöntemin kalanını bir iş parçacığında (genellikle bir iş parçacığı) bitirir.
Don Cheadle

çok özünde @geometrikal, async/awaitilgili serbest bırakarak .NET konu. awaitGerçekten zaman uyumsuz bir işlem yaptığınızda (.NET'in File.WriteAsync gibi), kullandığınız yöntemin geri kalanını askıya alır await, böylece arayan devam edebilir ve potansiyel olarak amacını bitirebilir. await-Ed işlemini bekleyen herhangi bir iplik engelleme veya bekleme yok . Eğer operasyon yaparken awaited tamamlandığında, geri kalan async/awaityöntemine bir iş parçacığı üzerinde konur ve (geri arama fikrine benzer) idam.
Don Cheadle
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.