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ì)象將完成。
- 3 回答
- 0 關(guān)注
- 517 瀏覽
添加回答
舉報(bào)