2017-07-15 23 views
-1

我想創建一個容器,每次我想要它的項目(迭代),它返回項目給我延遲真的我想要實現多種延遲(返回每個項目+延遲返回一些項目後延遲與計時器+延遲)。實現IEnumerable包含異步/等待任務

但我在下面的例子中簡化了這個想法。 以下代碼有效,但當我使用await Task.Delay(...)時出現問題。我在代碼中描述它(請閱讀評論)。

問題:

  • 有一個GetEnumerator方法來實現它的方式防止封鎖,迭代MyContainer object線程的?
  • 你有什麼有趣的方式來實現這個想法(任何有趣的解決方案)? :)

我認爲,很明顯,我想隱藏在IEnumerable<T>嵌入延遲機制。

我不會在List<int>上做出簡單的foreach包括延遲我的高級別課程。

我想用一個嵌入延遲機制做一個容器,最後只需在MyContainer之上使用foreach而沒有任何延遲(就像波紋管測試一樣)。

class MyContainer : IEnumerable<int> 
{ 
    private readonly int _sec; 
    private readonly List<int> _items; 
    public MyContainer(List<int> items, int sec) 
    { 
     this._sec = sec; 
     this._items = items; 
    } 

    public IEnumerator<int> GetEnumerator() 
    { 
     for (int i = 0; i < _items.Count(); ++i) 
     { 
      //----------------------------------------------------------------- 
      // It works but block caller thread (E.g. block UI Thread) 
      Thread.Sleep(Sec*1000); 

      //----------------------------------------------------------------- 
      //Problem line: 
      //Because return type of current method should be async Task<...> 
      //And it seems «yield» has problem with Task methods 
      //await Task.Delay(_sec*1000); // <<< Error line 

      //----------------------------------------------------------------- 
      yield return _items[i]; 
     } 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

測試上面的代碼Thread.Sleep(無await Task.Delay):

var myCnt=new MyContainer(new List<int>() {10,20,30,40,50}, 2); 
var sw=new Stopwatch(); 
sw.Start(); 

foreach (var item in myCnt) 
{ 
    Trace.WriteLine(sw.Elapsed); 
} 

sw.Stop(); 

// Result: 
// 00:00:02.0014343 
// 00:00:04.0034690 
// 00:00:06.0045362 
// 00:00:08.0056571 
// 00:00:10.0067891 
+1

目前尚不清楚你在做什麼。你希望你的迭代器包含一個延遲,但是你不想'foreach'被延遲?這聽起來可能是你需要的延遲/定時器應該在堆棧的不同部分實現。 –

+1

順便說一句,如果您使用'IAsyncEnumerable '的實現,則更容易混合異步/等待和枚舉類型,例如:https://github.com/tyrotoxin/AsyncEnumerable –

+0

@NateBarbettini,您的'IAsyncEnumerable '鏈接很有趣!你可以在這裏以你的評論爲例作爲答案嗎?如果他們想混合IEnumerable '和'像我這樣的任務,我認爲它將在這個問題頁面的未來幫助其他人。 鏈接: _幫助(a)創建一個元素提供程序,其中由於依賴於其他異步事件(例如,生成元素)可能需要很長時間。等待句柄,網絡流), (b)一個消費者在它們準備就緒時立即處理這些元素而不阻塞線程(而是在工作線程上調度處理)._ – RAM

回答

0

這應該讓你最的方式在概念上,你可以調整它。

這個想法是,它沒有阻塞,但每個屈服值可以用可控的延遲等待。

public static IEnumerable<Task<T>> EnumerateWithDelay<T>(Func<int, T> generator, Func<int, T, bool> limiter, TimeSpan delay) 
{ 
    var idx = 0; 
    while (true) 
    { 
     var item = generator(idx); 
     if (!limiter(idx, item)) yield break; 
     yield return Task.Delay(delay).ContinueWith(_ => item); 
     idx++; 
    } 
} 

public async Task A() 
{ 
    foreach (var itemTask in EnumerateWithDelay(idx => idx, (idx, val) => idx < 10, TimeSpan.FromSeconds(0.5))) 
    { 
     // I'll take .5 seconds 
     var number = await itemTask; 
    } 
} 

有了一些調整,你可以使發電機的功能不會被調用,直到後拖延了起來。