第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

如何在.NET中產(chǎn)生并等待實(shí)現(xiàn)控制流?

如何在.NET中產(chǎn)生并等待實(shí)現(xiàn)控制流?

慕斯709654 2019-12-10 10:48:42
據(jù)我了解yield,如果從迭代器塊內(nèi)部使用該關(guān)鍵字,它將控制流返回到調(diào)用代碼,并且當(dāng)再次調(diào)用該迭代器時(shí),它將從中斷的地方開始。同樣,await不僅要等待被調(diào)用方,而且還會(huì)將控制權(quán)返回給調(diào)用方,僅在調(diào)用方awaits方法時(shí)從中斷處接管。換句話說,沒有線程,異步和等待的“并發(fā)性”是由聰明的控制流引起的錯(cuò)覺,其細(xì)節(jié)被語法隱藏了?,F(xiàn)在,我是一名前匯編程序員,并且對(duì)指令指針,堆棧等非常熟悉,并且了解了正常的控制流程(子例程,遞歸,循環(huán),分支)的工作方式。但是這些新結(jié)構(gòu)-我不明白。當(dāng)await到達(dá),如何運(yùn)行時(shí)知道什么是一段代碼下一步應(yīng)該執(zhí)行?它如何知道何時(shí)可以從上次中斷的地方恢復(fù),以及如何記住在哪里?當(dāng)前調(diào)用堆棧發(fā)生了什么,是否以某種方式保存了它?如果調(diào)用方法在此之前進(jìn)行其他方法調(diào)用await怎么辦-為什么堆棧不被覆蓋?在異常和堆棧展開的情況下,運(yùn)行時(shí)到底將如何處理所有這些問題?何時(shí)yield到達(dá),運(yùn)行時(shí)如何跟蹤應(yīng)該拾取的點(diǎn)?迭代器狀態(tài)如何保存?
查看完整描述

3 回答

?
梵蒂岡之花

TA貢獻(xiàn)1900條經(jīng)驗(yàn) 獲得超5個(gè)贊

yield 是兩者中比較容易的一個(gè),所以讓我們檢查一下。


說我們有:


public IEnumerable<int> CountToTen()

{

  for (int i = 1; i <= 10; ++i)

  {

    yield return i;

  }

}

這被編譯一個(gè)位,如果我們想這樣寫的:


// Deliberately use name that isn't valid C# to not clash with anything

private class <CountToTen> : IEnumerator<int>, IEnumerable<int>

{

    private int _i;

    private int _current;

    private int _state;

    private int _initialThreadId = CurrentManagedThreadId;


    public IEnumerator<CountToTen> GetEnumerator()

    {

        // Use self if never ran and same thread (so safe)

        // otherwise create a new object.

        if (_state != 0 || _initialThreadId != CurrentManagedThreadId)

        {

            return new <CountToTen>();

        }


        _state = 1;

        return this;

    }


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


    public int Current => _current;


    object IEnumerator.Current => Current;


    public bool MoveNext()

    {

        switch(_state)

        {

            case 1:

                _i = 1;

                _current = i;

                _state = 2;

                return true;

            case 2:

                ++_i;

                if (_i <= 10)

                {

                    _current = _i;

                    return true;

                }

                break;

        }

        _state = -1;

        return false;

    }


    public void Dispose()

    {

      // if the yield-using method had a `using` it would

      // be translated into something happening here.

    }


    public void Reset()

    {

        throw new NotSupportedException();

    }

}

所以,還不如一個(gè)手寫的執(zhí)行效率IEnumerable<int>和IEnumerator<int>(例如,我們可能不會(huì)有一個(gè)單獨(dú)的浪費(fèi)_state,_i而且_current在這種情況下),但不壞(的伎倆再利用自身安全情況下這樣做,而不是創(chuàng)建一個(gè)新的對(duì)象是好的),并且可以擴(kuò)展以處理非常復(fù)雜的yield使用方法。


當(dāng)然,因?yàn)?/p>


foreach(var a in b)

{

  DoSomething(a);

}

是相同的:


using(var en = b.GetEnumerator())

{

  while(en.MoveNext())

  {

     var a = en.Current;

     DoSomething(a);

  }

}

然后,生成的MoveNext()被重復(fù)調(diào)用。


這種async情況幾乎是相同的原理,但是有一些額外的復(fù)雜性。重用另一個(gè)答案代碼中的示例,例如:


private async Task LoopAsync()

{

    int count = 0;

    while(count < 5)

    {

       await SomeNetworkCallAsync();

       count++;

    }

}

產(chǎn)生如下代碼:


private struct LoopAsyncStateMachine : IAsyncStateMachine

{

  public int _state;

  public AsyncTaskMethodBuilder _builder;

  public TestAsync _this;

  public int _count;

  private TaskAwaiter _awaiter;

  void IAsyncStateMachine.MoveNext()

  {

    try

    {

      if (_state != 0)

      {

        _count = 0;

        goto afterSetup;

      }

      TaskAwaiter awaiter = _awaiter;

      _awaiter = default(TaskAwaiter);

      _state = -1;

    loopBack:

      awaiter.GetResult();

      awaiter = default(TaskAwaiter);

      _count++;

    afterSetup:

      if (_count < 5)

      {

        awaiter = _this.SomeNetworkCallAsync().GetAwaiter();

        if (!awaiter.IsCompleted)

        {

          _state = 0;

          _awaiter = awaiter;

          _builder.AwaitUnsafeOnCompleted<TaskAwaiter, TestAsync.LoopAsyncStateMachine>(ref awaiter, ref this);

          return;

        }

        goto loopBack;

      }

      _state = -2;

      _builder.SetResult();

    }

    catch (Exception exception)

    {

      _state = -2;

      _builder.SetException(exception);

      return;

    }

  }

  [DebuggerHidden]

  void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0)

  {

    _builder.SetStateMachine(param0);

  }

}


public Task LoopAsync()

{

  LoopAsyncStateMachine stateMachine = new LoopAsyncStateMachine();

  stateMachine._this = this;

  AsyncTaskMethodBuilder builder = AsyncTaskMethodBuilder.Create();

  stateMachine._builder = builder;

  stateMachine._state = -1;

  builder.Start(ref stateMachine);

  return builder.Task;

}

它比較復(fù)雜,但是基本原理非常相似。最主要的復(fù)雜之處在于現(xiàn)在GetAwaiter()正在使用它。如果awaiter.IsCompleted檢查了任何時(shí)間,則true由于任務(wù)awaited已經(jīng)完成(例如,它可以同步返回),該方法將返回,然后該方法將繼續(xù)遍歷狀態(tài),否則將其自身設(shè)置為對(duì)等待者的回調(diào)。


究竟發(fā)生什么取決于等待者,包括觸發(fā)回調(diào)的原因(例如異步I / O完成,在線程上運(yùn)行的任務(wù)完成)以及對(duì)編組到特定線程或在線程池線程上運(yùn)行有什么要求,可能需要也可能不需要原始調(diào)用的上下文,依此類推。無論該等待者中的內(nèi)容是什么,都會(huì)調(diào)用MoveNext,它將繼續(xù)進(jìn)行下一個(gè)工作(直到下一個(gè)工作await),或者完成并返回,在這種情況下Task,實(shí)現(xiàn)的對(duì)象將完成。


查看完整回答
反對(duì) 回復(fù) 2019-12-10
  • 3 回答
  • 0 關(guān)注
  • 517 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)