2010-03-22 84 views
9

在python中,yield關鍵字可以用於推和上下文中,我知道如何在c#中執行pull上下文,但是如何實現push。我後我試圖從蟒蛇在C#複製代碼:你怎麼能使用C#做協同例程?

def coroutine(func): 
    def start(*args,**kwargs): 
    cr = func(*args,**kwargs) 
    cr.next() 
    return cr 
    return start 

@coroutine 
def grep(pattern): 
    print "Looking for %s" % pattern 
    try: 
    while True: 
     line = (yield) 
     if pattern in line: 
     print line, 
    except GeneratorExit: 
    print "Going away. Goodbye" 
+0

Eric Lippert在此處有一篇博客文章 – 2010-03-22 15:10:08

+1

考慮使用製表符/空格來更多地對代碼進行格式化。 – Mizipzor 2010-03-22 15:17:31

+3

標籤格式...確實是必要的,而不是時間的問題,是python的問題。 – 2010-03-22 15:38:47

回答

13

如果你想要的是一個「觀察到的集合」 - 也就是說,它在你推動的結果,而不是讓消費者拉他們一家集 - 那麼你可能要考慮無功框架擴展。下面是關於它的一個文章:

http://www.infoq.com/news/2009/07/Reactive-Framework-LINQ-Events

現在,你注意,你可以很容易地建立既「推」和「拉」風格的迭代器,如果您有可用的協同程序。 (或者,正如托馬斯指出,你可以用延續建造它們。)在C#的當前版本我們沒有真正的協同程序(或延續)。但是,我們非常關心用戶感受異步編程的痛苦。

將基於光纖的協同程序作爲第一類語言功能實現是一種可能用於使異步編程更容易的技術,但這只是我們目前正在研究的許多可能的想法。如果你有一個非常可靠的場景,其中協程比其他任何地方都做得更好 - 包括響應式框架 - 那麼我很樂意聽到更多關於它的信息。關於人們在異步編程中遇到的實際問題,我們所掌握的更真實的數據越有可能我們想出一個好的解決方案。謝謝!

更新:我們最近宣佈,我們正在向C#和VB的下一個版本添加類似於協程的異步控制流。您可以使用我們的社區技術預覽版本自行嘗試,您可以下載here

+0

其中一種情況是事件驅動模擬(Simula風格)。我有一個項目使用Win32光纖,我仍然無法移植到.NET – 2010-03-22 23:12:34

+0

我認爲C#中的異步編程非常棒。 雖然我喜歡F#中的Erlang風格的MailboxProcessor。 至於協同例程,我覺得它們非常有趣。我知道它們是舊技術,並且在線程被引入時被掃除,但我喜歡這樣的想法,即我知道一個例程何時執行以及何時將控制權交還。我發現線程的主要問題是缺乏控制力和創建它們的一般沉重感。然而,他們提供了一個很好的思想抽象層次,需要很少的努力來實現:) – WeNeedAnswers 2010-03-22 23:14:56

+0

謝謝埃裏克。這聽起來很有希望! – WeNeedAnswers 2011-07-27 19:44:08

6

C#沒有一般協同例程。一般的協同程序是協程序有自己的棧,即它可以調用其他方法,這些方法可以「產生」值。一般協同例程的實現需要使用堆棧來實現一些聰明的事情,可能直至並且包括在堆上分配棧幀(包含本地變量的隱藏結構)。這可以做到,有些語言可以做到這一點(例如Scheme),但要做到這一點有些棘手。另外,許多程序員發現這個特性很難理解。

通用協程可以用線程模擬。每個線程都有自己的堆棧。在一個協同例程設置中,兩個線程(初始調用者和協程的線程)將交替控制,它們將永遠不會同時運行。然後「yield」機制是兩個線程之間的交換,因此它是昂貴的(同步,OS內核和調度程序的往返...)。此外,還有很多內存泄漏的空間(協程必須明確「停止」,否則等待的線程將永久保留)。因此,這很少完成。

C#提供了一個稱爲迭代器的混搭式協同例程功能。 C#編譯器會自動將迭代器代碼轉換爲特定的狀態類,局部變量將變爲類字段。然後在虛擬機級別產生一個普通的return。只要從迭代器代碼本身執行「yield」,而不是由迭代器代碼調用的方法執行,這樣的事情就是可行的。 C#迭代器已經覆蓋了很多用例,而C#設計人員不願意再去continuations。有些諷刺的人們熱衷於指出,實現全功能的延續會阻止C#被作爲其頭號敵人Java作爲有效(有效延續是可行的,但這需要與GC和JIT編譯器頗有些工作)。

+0

很好的答案。我想我發現了我正在試圖用C#,IObservable做什麼。關於堆棧的東西,Python下面是否會這樣做,因爲我不認爲它確實如此。它使用香草C.儘管我不確定。我試圖避免使用所有線程,因此爲什麼我對協同例程感興趣。我發現如果我完全掌握了我的編程,並且有了避免線程的工具,爲什麼不嘗試。協程的東西應該工作一個治療都包裝在IObservable假:) :) – WeNeedAnswers 2010-03-22 15:48:04

+0

Java高效... :)對不起,讓我微笑。我記得使用JBoss做了一個解決方案。我們告訴我們的最終客戶(T.U.I. ---托馬斯庫克),他需要偶爾再次打開和關閉它。 :) – WeNeedAnswers 2010-03-22 16:03:09

+1

如果你不喜歡Java,效率明智,那麼你很可能不會對C#感到高興。在這方面他們非常相似。其實他們在各方面都很相似。 – 2010-03-22 16:26:15

0

我很想看到.Net的基於光纖的API。

我試圖在C#中通過p/invoke a使用本地光纖API,但由於運行時的異常處理(錯誤地)使得基於線程的假設,事件在發生異常時破壞(嚴重)。

基於光纖協同API的一個「殺手級應用」是遊戲編程;某些類型的AI需要一個「輕量級」線程,您可以隨意分時切分。例如,遊戲行爲樹需要能夠在每一幀「脈衝」決策代碼,允許AI代碼在決策片啓動時合作地退回給調用者。這可以用硬線程來實現,但要複雜得多。因此,雖然真正的光纖使用案例並不是主流,但它們絕對存在,如果光纖子系統中存在的缺陷已經制定出來,我們的一小部分.Net編碼器將大力振作起來。

1

實際上,.NET並沒有對線程關聯做出「不正確的假設」,實際上它完全將OS級線程的概念與操作系統級線程分離開來。

你需要做的是將一個邏輯.NET線程狀態與你的光纖相關聯(爲此你需要CLR Hosting API,但是你不需要自己編寫主機,你可以直接使用你自己的應用程序所需的那些) )和一切,鎖定跟蹤,異常處理再次正常工作。

一個例子可以在這裏找到:http://msdn.microsoft.com/en-us/magazine/cc164086.aspx

順便說一句單聲道2.6包含低水平協程支持,可以用來方便地實現所有更高級別的原語。

0

那麼,我試着開發一個完整的庫來管理只有一個線程的協同程序。最難的部分是在協程內部調用協程...並返回參數,但最終我達到了相當好的結果here。唯一的警告是阻塞I/O操作必須通過任務完成,alll「return」必須替換爲「yield return」。 使用基於這個庫的應用服務器,我能夠幾乎使用基於IIS的標準異步/等待進行的請求的兩倍。 (在github上尋找Node.Cs和Node.Cs.Musicstore以在家嘗試)