2009-12-01 40 views
210

(很久以前)我寫了一個多線程的web-spider來同時啓用併發請求。那是在我的Python青年時代,在我知道GIL之前的日子以及它爲多線程代碼創建的相關困境(IE,大多數時候東西剛剛結束序列化!)...一個乾淨,輕量級的替代Python的扭曲?

我想修改此代碼以使其更健壯並且性能更好。基本上有兩種方法可以做到這一點:我可以在2.6+中使用新的multiprocessing module,或者我可以選擇某種基於反應堆/事件的模型。我寧願做更晚,因爲它更簡單,更不容易出錯。

所以這個問題涉及什麼框架最適合我的需求。以下是我知道的,到目前爲止選項列表:

  • Twisted:Python的反應器框架的鼻祖:看起來複雜,有點臃腫不過。陡峭的學習曲線爲一個小任務。
  • Eventlet:從lindenlab的傢伙。基於Greenlet的框架適用於這些類型的任務。儘管我看了一下代碼,但它並不太漂亮:非pep8兼容,分散打印(爲什麼人們在框架中這樣做?),API看起來有點不一致。
  • PyEv:不成熟,現在似乎沒有人使用它,雖然它基於libevent,所以它有一個堅實的後端。
  • asyncore:從stdlib:über的低級別,看起來像是一個涉及很多legwork只是爲了讓東西離開地面。
  • tornado:雖然這是一款面向服務器的產品,專爲服務器動態網站而設計,但它的特色是async HTTP client和簡單的ioloop。看起來它可以完成工作,但不是它的目標。 [編輯:不能在Windows上運行不幸的是,它計算出來好嗎 - 它要求我支持這個跛腳平臺]

有什麼我已經錯過呢?當然,必須有一個圖書館適合簡化的異步網絡庫的甜蜜點!

[編輯:非常感謝intgr他指向this page。如果你滾動到底部,你會看到有一個非常好的項目列表,旨在以這種或那種方式解決這個任務。事實上,自Twisted成立以來事情確實發生了變化:現在人們似乎贊成基於co-routine的解決方案,而不是傳統的反應器/回調定向解決方案。這種方法的好處是更直接的代碼:我以前肯定發現,特別是在C++中使用boost.asio時,基於回調的代碼可能會導致難以遵循的設計,並且對未經訓練的代碼相對模糊眼。使用協同例程可以讓你編寫至少看起來更加同步的代碼。我想現在我的任務是弄清楚我喜歡這些圖書館中的哪一個,並給它一個去!很高興我現在問...]

[編輯:也許感興趣的人誰遵循或無意中發現了這個這個問題或關心這個話題在任何意義上:我發現the available tools當前狀態的一個真正偉大的書面記錄這份工作]

+14

Python的* *是多線程的,它只是不允許兩個線程同時運行Python代碼。 – intgr

+1

@Intgr:的確如此,理論上,因爲'socket'是一個C模塊,所以如果他們在調用底層例程之前讓GIL走,事情可能實際上是併發的。即使如此,我想我想回到單線程的東西。 – jkp

+82

我從你的問題中學到的東西比從答案中學到的要多得多。 –

回答

27

我喜歡concurrence Python模塊,它依靠Stackless Python microthreads或Greenlets來實現輕量級線程。所有阻塞網絡I/O通過一個單獨的libevent循環透明地變爲異步,因此它應該幾乎與真正的異步服務器一樣高效。

我想這種方法和Eventlet很相似。

缺點是它的API與Python的sockets/threading模塊有很大不同;你需要重寫應用程序的公平位(或寫兼容性墊片層)

編輯:看來,有也cogen,這是類似的,但使用Python 2.5的增強發電機其協同程序,而不是Greenlets。這使得它比並發和其他替代方案更具可移植性。網絡I/O直接使用epoll/kqueue/iocp完成。

+0

@intgr:很棒的鏈接。我之前曾經見過這兩個人,那些是我希望看到的那些東西。 +1 – jkp

+3

看起來好像是四年前的最後一次更新,併發是一個死去的項目。 – Gewthen

+0

項目已經死了,Hyves也是如此! –

97

扭曲是複雜的,你是對的。扭曲的是不是臃腫。

如果你到這裏看看:http://twistedmatrix.com/trac/browser/trunk/twisted,你會發現一個有組織的,全面的,非常行之有效的互聯網許多協議套件,以及幫助代碼編寫和部署非常複雜的網絡應用。我不會把膨脹與全面性混爲一談。

衆所周知,Twisted文檔從乍看起來並不是最容易用戶使用的,我相信這會讓不幸的人數變多。但是如果你投入時間,扭曲是驚人的(恕我直言)。我做了,事實證明它是值得的,我建議其他人也嘗試一樣。

+4

@clemesha:也許你是對的,並沒有被加載,但它確實覺得讓我的頭腦做些簡單的事情有點太過分了。我理解異步編程,我在C++中使用boost :: asio工作,所以這些概念並不新鮮,但它與扭曲的東西相互競爭:它是一個全新的世界,很像django用於web的東西。再次,當我在做web的時候,我使用輕量級的WSGI代碼,並且只將我需要的東西插在一起。我想要的課程馬匹。 – jkp

+7

@clemesha:呃,今天我冒昧地看看:扭曲的重量在20MB!即使核心是12MB ....如果這不是臃腫,我不知道什麼是。 – jkp

+29

基本的Twisted APIs非常小(反應堆,延期協議)。大多數Twisted代碼是使用這些基礎的異步協議實現。 「膨脹」在這裏不是一個有用的形容詞(或在大多數情況下)。扭曲的大小對於它所做的事情是合理的。 – daf

15

這些解決方案都不會避免GIL阻止CPU並行性這一事實 - 它們只是獲得線程已有的IO並行性的更好方法。如果你認爲你可以做更好的IO,通過一切手段追求其中的一個,但是如果你的瓶頸在處理結果,除了多處理模塊外,這裏沒有任何幫助。

+0

使用多個進程有什麼問題? –

+3

什麼也沒有,因此建議使用多處理模塊。 –

8

Kamaelia尚未提及。其併發模型基於將收件箱和發件箱之間消息傳遞的組件連接在一起。 Here的簡要概述。

+5

我用一個應用程序kamaelia - 這是非常痛苦的。恕我直言,還有其他更好的python concurrenct選項(其中大部分都在上面提到過) –

11

我不會去調用扭曲的臃腫,但它很難包圍你的頭。我避免在一段時間內學習一段時間,因爲我一直想要一些「小任務」更容易的事情。

但是,現在我已經與它合作了一些,我必須說,包括所有電池都非常好。

我所使用過的所有其他異步庫最終都不如它們出現的成熟。 Twisted的事件循環是穩定的。

我不太清楚如何解決扭曲的陡峭的學習曲線。如果有人願意將它分叉並清理一些東西,比如清除所有向後兼容性和死亡項目,這可能會有所幫助。但這是我猜測成熟軟件的本質。

+0

如果你曾經查過在Windows下如何實現gtk反應堆(每10ms硬核輪詢:http://twistedmatrix.com/trac/browser /trunk/twisted/internet/_glibbase.py?rev=37416#L378),你不會稱之爲「成熟」...... – schlamar

+2

Hi @schlamar。這個令人討厭的黑客手段被實施爲GTK +中一些非常嚴重的錯誤的解決方法,早在功率效率問題上就不那麼值得關注了。但是,Twisted的美妙之處在於,我們可以只有這個bug *,在框架中修復它,並且我們的用戶不需要關心它。你想提供一個解決這個問題的解決方案,並擺脫(棄用,然後刪除)'PortableGtkReactor'? – Glyph

+1

@Glyph我在https://twistedmatrix.com/trac/ticket/4744#comment:2上添加了有用的建議,如果有人想解決這個問題,因爲這些問題仍然存在。順便說一句,你可以通過調度兩個事件循環之間的回調來更有效地解決這個問題。 – schlamar

56

geventeventlet cleaned up

在API方面,它遵循與標準庫(特別是線程和多處理模塊)相同的約定,因爲它是有意義的。所以你有熟悉的東西,如QueueEvent來處理。

它僅支持libevent更新:libev since 1.0)作爲反應器實現,但需要它充分利用的基礎上,配備了快速WSGI服務器的libevent-HTTP和解決通過的libevent的DNS DNS查詢,而不是使用一個線程池像大多數其他圖書館一樣。 (更新:自1.0 C-頃用於使異步DNS查詢;線程池也是一種選擇。)

喜歡eventlet,它使回調和Deferreds通過使用greenlets不必要的。

查看示例:concurrent download of multiple urlslong polling webchat

+4

我會第二次gevent - 在回顧了許多解決方案後,gevent對我來說工作得非常好。它使我能夠保留現有程序中較好的一部分,並且所需的更改是微不足道的 - 最重要的是,如果代碼需要在3年,4年,5年......時間內維護,它仍然會使有意義的,不熟悉GEVENT,爲扭轉最大的攪局者是濃厚的學習曲線,這會導致問題不只是在實現時,也將進一步向下維護期間行... – Carpetsmoker

27

NicholasPiël在他的博客中編寫了一個真正的interesting comparison這樣的框架:它非常值得一讀!

+2

雖然我同意,文章是一個有趣的閱讀,我認爲值得考慮提出的基準的有效性。 請參閱此處的評論:http://www.reddit.com/r/programming/comments/ahepg/benchmark_of_asynchronous_servers_in_python/ – clemesha

+1

@clemesha,雖然reddit頁面中的一點值得注意,但基準測試是在雙核機器,並可能沒有遭受致命缺陷的描述。我想這可能* *在客戶端和服務器運行在相同的核心,但它似乎並不可能。 –

4

關於這個問題有一本很好的書:Abe Fettig編寫的「Twisted Network Programming Essentials」。這些例子展示瞭如何編寫Pythonic代碼,對我個人而言,不要以我爲基礎的臃腫框架。看看書中的解決方案,如果它們不乾淨,那麼我不知道乾淨的手段。

我唯一的謎團就是和其他框架一樣,比如Ruby。我擔心,它會擴大嗎?我討厭將一個客戶端提交給一個將會有可伸縮性問題的框架。

2

也試試Syncless。它是基於協同的(所以它類似於Concurrence,Eventlet和gevent)。它爲socket.socket,socket.gethostbyname(等),ssl.SSLSocket,time.sleep和select.select實現了嵌入式非阻塞替換。它很快。它需要Stackless Python和libevent。它包含用C(Pyrex/Cython)編寫的強制性Python擴展。

7

我已經開始使用扭曲的一些東西。它的美麗幾乎是因爲它「臃腫」。有幾乎所有主要協議的連接器。你可以擁有一個jabber機器人,它可以接受命令併發布到irc服務器,通過電子郵件發送給某人,運行命令,從NNTP服務器讀取數據,並監控網頁中的變化。壞消息是它可以做到所有這一切,並且可以使OP解釋的簡單任務過於複雜。 python的優點是你只包含你需要的東西。因此,雖然下載可能是20MB,但您可能只包含2mb的庫(這仍然很多)。我最大的抱怨是,儘管它們包含了例子,除了你自己的基本tcp服務器之外的任何東西。

雖然不是python解決方案,但我已經看到node.js在後期獲得更多的牽引力。實際上,我考慮過爲較小的項目考慮,但當我聽到javascript時,我只是畏縮了:)

+0

我是一個大的Python粉絲。 - 查看Douglas Crockford的「Javascript - The good parts」(3,4個視頻)。並查看CoffeeScript。事實證明,JS有Python的東西,除了Syntax,哈哈。 CS試圖減輕,但對一個有點笨拙... –

4

Whizzer是一個使用pyev的小型異步套接字框架。它非常快,主要是因爲pyev。它試圖提供一個類似的界面,只是稍微改變一下而已。

2

我確認syncless的好處。它可以使用libev(libevent的更新,更清潔和更好的性能版本)。前一段時間它沒有Libevent那麼多的支持,但是現在開發過程進一步發展並且非常有用。

0

歡迎您來看看PyWorks,它採用了一種完全不同的方法。它允許對象實例在自己的線程中運行,並對該對象進行異步調用。

只是讓一個類從Task而不是Object繼承而來,它是異步的,所有的方法調用都是代理。返回值(如果你需要的話)是未來的代理。

res = obj.method(args) 
# code continues here without waiting for method to finish 
do_something_else() 
print "Result = %d" % res # Code will block here, if res not calculated yet 

PyWorks可以http://bitbucket.org/raindog/pyworks

+1

雖然這是有趣的,可能對於某些任務是合適的,使用線程聯網進行不良(尤其是關於Python由於GIL)。這正是問題:一個平坦的框架或多處理。所以你的答案顯然是超出了範圍... – schlamar

1

如果你只是想一個簡化的,輕量級的HTTP請求庫,然後我發現Unirest真的很好找到