欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

C#中異步迭代器的原理是什么

這篇文章將為大家詳細(xì)講解有關(guān)C#中異步迭代器的原理是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。

目前累計(jì)服務(wù)客戶上千,積累了豐富的產(chǎn)品開發(fā)及服務(wù)經(jīng)驗(yàn)。以網(wǎng)站設(shè)計(jì)水平和技術(shù)實(shí)力,樹立企業(yè)形象,為客戶提供網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、網(wǎng)站策劃、網(wǎng)頁設(shè)計(jì)、網(wǎng)絡(luò)營銷、VI設(shè)計(jì)、網(wǎng)站改版、漏洞修補(bǔ)等服務(wù)。創(chuàng)新互聯(lián)建站始終以務(wù)實(shí)、誠信為根本,不斷創(chuàng)新和提高建站品質(zhì),通過對領(lǐng)先技術(shù)的掌握、對創(chuàng)意設(shè)計(jì)的研究、對客戶形象的視覺傳遞、對應(yīng)用系統(tǒng)的結(jié)合,為客戶提供更好的一站式互聯(lián)網(wǎng)解決方案,攜手廣大客戶,共同發(fā)展進(jìn)步。

迭代器的概念

迭代器的概念在C#中出現(xiàn)的比較早,很多人可能已經(jīng)比較熟悉了。

通常迭代器會用在一些特定的場景中。

舉個(gè)例子:有一個(gè)foreach循環(huán):

foreach (var item in Sources)
{
    Console.WriteLine(item);
}
 

這個(gè)循環(huán)實(shí)現(xiàn)了一個(gè)簡單的功能:把Sources中的每一項(xiàng)在控制臺中打印出來。

有時(shí)候,Sources可能會是一組完全緩存的數(shù)據(jù),例如:List<string>

IEnumerable<string> Sources(int x)
{
    var list = new List<string>();
    for (int i = 0; i < 5; i++)
        list.Add($"result from Sources, x={x}, result {i}");
    return list;
}
 

這里會有一個(gè)小問題:在我們打印Sources的第一個(gè)的數(shù)據(jù)之前,要先運(yùn)行完整運(yùn)行Sources()方法來準(zhǔn)備數(shù)據(jù),在實(shí)際應(yīng)用中,這可能會花費(fèi)大量時(shí)間和內(nèi)存。更有甚者,Sources可能是一個(gè)無邊界的列表,或者不定長的開放式列表,比方一次只處理一個(gè)數(shù)據(jù)項(xiàng)目的隊(duì)列,或者本身沒有邏輯結(jié)束的隊(duì)列。

這種情況,C#給出了一個(gè)很好的迭代器解決:

IEnumerable<string> Sources(int x)
{
    for (int i = 0; i < 5; i++)
        yield return $"result from Sources, x={x}, result {i}";
}
 

這個(gè)方式的工作原理與上一段代碼很像,但有一些根本的區(qū)別 - 我們沒有用緩存,而只是每次讓一個(gè)元素可用。

為了幫助理解,來看看foreach在編譯器中的解釋:

using (var iter = Sources.GetEnumerator())
{
    while (iter.MoveNext())
    {
        var item = iter.Current;
        Console.WriteLine(item);
    }
}
 

當(dāng)然,這個(gè)是省略掉很多東西后的概念解釋,我們不糾結(jié)這個(gè)細(xì)節(jié)。但大體的意思是這樣的:編譯器對傳遞給foreach的表達(dá)式調(diào)用GetEnumerator(),然后用一個(gè)循環(huán)去檢查是否有下一個(gè)數(shù)據(jù)(MoveNext()),在得到肯定答案后,前進(jìn)并訪問Current屬性。而這個(gè)屬性代表了前進(jìn)到的元素。

?

上面這個(gè)例子,我們通過MoveNext()/Current方式訪問了一個(gè)沒有大小限制的向前的列表。我們還用到了yield迭代器這個(gè)很復(fù)雜的東西 - 至少我是這么認(rèn)為的。

我們把上面的例子中的yield去掉,改寫一下看看:

IEnumerable<string> Sources(int x) => new GeneratedEnumerable(x);

class GeneratedEnumerable : IEnumerable<string>
{
    private int x;
    public GeneratedEnumerable(int x) => this.x = x;

    public IEnumerator<string> GetEnumerator() => new GeneratedEnumerator(x);

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

class GeneratedEnumerator : IEnumerator<string>
{
    private int x, i;
    public GeneratedEnumerator(int x) => this.x = x;

    public string Current { get; private set; }

    object IEnumerator.Current => Current;

    public void Dispose() { }

    public bool MoveNext()
    {
        if (i < 5)
        {
            Current = $"result from Sources, x={x}, result {i}";
            i++;
            return true;
        }
        else
        {
            return false;
        }
    }

    void IEnumerator.Reset() => throw new NotSupportedException();
}
 

這樣寫完,對照上面的yield迭代器,理解工作過程就比較容易了:

  1. 首先,我們給出一個(gè)對象IEnumerable。注意,IEnumerableIEnumerator是不同的。

  2. 當(dāng)我們調(diào)用Sources時(shí),就創(chuàng)建了GeneratedEnumerable。它存儲狀態(tài)參數(shù)x,并公開了需要的IEnumerable方法。

  3. 后面,在需要foreach迭代數(shù)據(jù)時(shí),會調(diào)用GetEnumerator(),而它又調(diào)用GeneratedEnumerator以充當(dāng)數(shù)據(jù)上的游標(biāo)。

  4. MoveNext()方法邏輯上實(shí)現(xiàn)了for循環(huán),只不過,每次調(diào)用MoveNext()只執(zhí)行一步。更多的數(shù)據(jù)會通過Current回傳過來。另外補(bǔ)充一點(diǎn):MoveNext()方法中的return false對應(yīng)于yield break關(guān)鍵字,用于終止迭代。

是不是好理解了?

?

下面說說異步中的迭代器。

 

異步中的迭代器

上面的迭代,是同步的過程。而現(xiàn)在Dotnet開發(fā)工作更傾向于異步,使用async/await來做,特別是在提高服務(wù)器的可伸縮性方面應(yīng)用特別多。

上面的代碼最大的問題,在于MoveNext()。很明顯,這是個(gè)同步的方法。如果它運(yùn)行需要一段時(shí)間,那線程就會被阻塞。這會讓代碼執(zhí)行過程變得不可接受。

我們能做得最接近的方法是異步獲取數(shù)據(jù):

async Task<List<string>> Sources(int x) {...}
 

但是,異步獲取數(shù)據(jù)并不能解決數(shù)據(jù)緩存延遲的問題。

好在,C#為此特意增加了對異步迭代器的支持:

public interface IAsyncEnumerable<out T>
{
    IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default);
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
    T Current { get; }
    ValueTask<bool> MoveNextAsync();
}
public interface IAsyncDisposable
{
    ValueTask DisposeAsync();
}
 

注意,從.NET Standard 2.1.NET Core 3.0開始,異步迭代器已經(jīng)包含在框架中了。而在早期版本中,需要手動引入:

# dotnet add package Microsoft.Bcl.AsyncInterfaces
 

目前這個(gè)包的版本號是5.0.0。

?

還是上面例子的邏輯:

IAsyncEnumerable<string> Source(int x) => throw new NotImplementedException();
 

看看foreach可以await后的樣子:

await foreach (var item in Sources)
{
    Console.WriteLine(item);
}
 

編譯器會將它解釋為:

await using (var iter = Sources.GetAsyncEnumerator())
{
    while (await iter.MoveNextAsync())
    {
        var item = iter.Current;
        Console.WriteLine(item);
    }
}
 

這兒有個(gè)新東西:await using。與using用法相同,但釋放時(shí)會調(diào)用DisposeAsync,而不是Dispose,包括回收清理也是異步的。

這段代碼其實(shí)跟前邊的同步版本非常相似,只是增加了await。但是,編譯器會分解并重寫異步狀態(tài)機(jī),它就變成異步的了。原理不細(xì)說了,不是本文關(guān)注的內(nèi)容。

那么,帶有yield的迭代器如何異步呢?看代碼:

async IAsyncEnumerable<string> Sources(int x)
{
    for (int i = 0; i < 5; i++)
    {
        await Task.Delay(100); // 這兒模擬異步延遲
        yield return $"result from Sources, x={x}, result {i}";
    }
}
 

嗯,看著就舒服。

?

這就完了?圖樣圖森破。異步有一個(gè)很重要的特性:取消。

那么,怎么取消異步迭代?

 

異步迭代的取消

異步方法通過CancellationToken來支持取消。異步迭代也不例外??纯瓷厦?code>IAsyncEnumerator<T>的定義,取消標(biāo)志也被傳遞到了GetAsyncEnumerator()方法中。

那么,如果是手工循環(huán)呢?我們可以這樣寫:

await foreach (var item in Sources.WithCancellation(cancellationToken).ConfigureAwait(false))
{
    Console.WriteLine(item);
}
 

這個(gè)寫法等同于:

var iter = Sources.GetAsyncEnumerator(cancellationToken);
await using (iter.ConfigureAwait(false))
{
    while (await iter.MoveNextAsync().ConfigureAwait(false))
    {
        var item = iter.Current;
        Console.WriteLine(item);
    }
}
 

沒錯,ConfigureAwait也適用于DisposeAsync()。所以最后就變成了:

await iter.DisposeAsync().ConfigureAwait(false);
 

?

異步迭代的取消捕獲做完了,接下來怎么用呢?

看代碼:

IAsyncEnumerable<string> Sources(int x) => new SourcesEnumerable(x);
class SourcesEnumerable : IAsyncEnumerable<string>
{
    private int x;
    public SourcesEnumerable(int x) => this.x = x;

    public async IAsyncEnumerator<string> GetAsyncEnumerator(CancellationToken cancellationToken = default)
    {
        for (int i = 0; i < 5; i++)
        {
            await Task.Delay(100, cancellationToken); // 模擬異步延遲
            yield return $"result from Sources, x={x}, result {i}";
        }
    }
}
 

如果有CancellationToken通過WithCancellation傳過來,迭代器會在正確的時(shí)間被取消 - 包括異步獲取數(shù)據(jù)期間(例子中的Task.Delay期間)。當(dāng)然我們還可以在迭代器中任何一個(gè)位置檢查IsCancellationRequested或調(diào)用ThrowIfCancellationRequested()。

此外,編譯器也會通過[EnumeratorCancellation]來完成這個(gè)任務(wù),所以我們還可以這樣寫:

async IAsyncEnumerable<string> Sources(int x, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
    for (int i = 0; i < 5; i++)
    {
        await Task.Delay(100, cancellationToken); // 模擬異步延遲
        yield return $"result from Sources, x={x}, result {i}";
    }
}
 

這個(gè)寫法與上面的代碼其實(shí)是一樣的,區(qū)別在于加了一個(gè)參數(shù)。

實(shí)際應(yīng)用中,我們有下面幾種寫法上的選擇:

// 不取消
await foreach (var item in Sources)

// 通過WithCancellation取消
await foreach (var item in Sources.WithCancellation(cancellationToken))

// 通過SourcesAsync取消
await foreach (var item in SourcesAsync(cancellationToken))

// 通過SourcesAsync和WithCancellation取消
await foreach (var item in SourcesAsync(cancellationToken).WithCancellation(cancellationToken))

// 通過不同的Token取消
await foreach (var item in SourcesAsync(tokenA).WithCancellation(tokenB))

關(guān)于C#中異步迭代器的原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

名稱欄目:C#中異步迭代器的原理是什么
URL地址:http://aaarwkj.com/article12/pdigdc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、動態(tài)網(wǎng)站網(wǎng)站排名、外貿(mào)建站、全網(wǎng)營銷推廣做網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
欧美老熟妇一区二区三区| 91九色国产成人久久精品| 夫妻爱爱视频在线观看| 亚洲国产精品福利在线| 人妻久久久久久精品99| 日韩最新人妻在线不卡| 三级视频一区二区三区| 久久婷婷国产综合色啪| 色国产精品一区在线观看| 日韩高清av一区二区| 91九色午夜在线观看| 中国的性生活黄片免费观看| 日韩视频专区一区二区| 欧美特黄在线免费观看| 黑寡妇精品欧美一区二区毛 | 亚洲女人淫片在线观看| 日韩精品中文字幕欧美激情| av天堂官网在线人妻| 欧美国产激情一区二区| 欧美日本国产专区一区| 人妖伪娘在线观看一区二区三区 | 日韩欧美一区二区在线播放| 亚洲久久精品一区二区| 日韩人妻精品在线一区二区| av中文字幕熟妇人妻少妇| 岛国毛片在线免费播放| 很黄无遮挡在线免费网站| 看夫妻性生活免费视频| 青青草原免费在线观看| 国产三级精品久久三级国专区| 日韩女优在线播放一区二区| 国产一区二区三区的网站| 少妇诱惑一区二区三区| 日本中文有码视频在线观看| 国产av麻豆全部免费| 日韩精品欧美视频久久| 91香蕉伊人综合久久麻豆| 久久精品一区二区东京热| 高清不卡一区二区在线观看| 日韩在线不卡免费视频一区| 亚洲精品你懂的av在线|