2009-07-31 80 views
8

我剛剛玩了一點python和線程,並且即使在多線程腳本中也實現了DNS請求被阻止。從螺紋進口螺紋 進口插座Python解釋器塊多線程DNS請求?

class Connection(Thread): 
    def __init__(self, name, url): 
     Thread.__init__(self) 
     self._url = url 
     self._name = name 

    def run(self): 
     print "Connecting...", self._name 
     try: 
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
      s.setblocking(0) 
      s.connect((self._url, 80)) 
     except socket.gaierror: 
      pass #not interested in it 
     print "finished", self._name 


if __name__ == '__main__': 
    conns = [] 
    # all invalid addresses to see how they fail/check times 
    conns.append(Connection("conn1", "www.2eg11erdhrtj.com")) 
    conns.append(Connection("conn2", "www.e2ger2dh2rtj.com")) 
    conns.append(Connection("conn3", "www.eg2de3rh1rtj.com")) 
    conns.append(Connection("conn4", "www.ege2rh4rd1tj.com")) 
    conns.append(Connection("conn5", "www.ege52drhrtj1.com")) 

    for conn in conns: 
     conn.start() 

我不知道超時究竟有多長

,但運行這個當出現以下情況:考慮下面的腳本

  1. 所有線程開始我得到我的打印輸出
  2. 每xx秒,一個線程顯示完成,而不是一次全部
  3. T他線程順序完成,並不是所有的一次(超時=相同的所有!)

所以我唯一的猜測是,這與GIL?很明顯,線程不會同時執行任務,每次只嘗試一個連接。

有沒有人知道解決這個問題的方法?

asyncore犯規的幫助,我寧願不使用現在扭曲) 是不是有可能得到與Python做這個簡單的小東西?

問候,湯姆

編輯:

我MacOSX上,我只是讓我的朋友在linux上運行這一點,他其實得到我希望得到的結果。即使在非Threaded環境中,他的socket.connects()也會立即返回。即使他將套接字設置爲阻塞,並且超時至10秒,他所有的線程也同時完成。

任何人都可以解釋這一點嗎?

+1

您是否嘗試過只用socket.getaddrinfo(主機,端口),看看是否有相同的限制?我不幸無法複製這個,因爲這是一個DNS問題。在大多數情況下,您應該快速地獲得「gaierror:(-2,'名稱或服務未知')」。 – JimB 2009-07-31 14:28:02

+0

是的我已經試過這個,它有相同的限制。 – Tom 2009-07-31 14:30:53

+0

我很確定OSX使用BSD庫中的getaddrinfo,它可能具有下面列出的限制。 「 – JimB 2009-07-31 14:37:12

回答

15

在某些系統上,getaddrinfo不是線程安全的。 Python認爲一些這樣的系統是FreeBSD,OpenBSD,NetBSD,OSX和VMS。在這些系統上,Python專門爲netdb(即getaddrinfo和friends)維護一個鎖。

所以,如果你不能切換操作系統,你將不得不使用不同的(線程安全的)解析器庫,如twisted。

2

是否適合你可以使用multiprocessing模塊,允許異步使用Twisted Names基於流程的並行

import multiprocessing, socket 

NUM_PROCESSES = 5 

def get_url(url): 
    try: 
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     s.setblocking(0) 
     s.connect((url, 80)) 
    except socket.gaierror: 
     pass #not interested in it 
    return 'finished ' + url 


def main(url_list): 
    pool = multiprocessing.Pool(NUM_PROCESSES) 
    for output in pool.imap_unordered(get_url, url_list): 
     print output 

if __name__=="__main__": 
    main(""" 
      www.2eg11erdhrtj.com 
      www.e2ger2dh2rtj.com 
      www.eg2de3rh1rtj.com 
      www.ege2rh4rd1tj.com 
      www.ege52drhrtj1.com 
      """.split()) 
1

發送DNS請求:

import sys 
from twisted.internet import reactor 
from twisted.internet import defer 
from twisted.names import client 
from twisted.python import log 

def process_names(names): 
    log.startLogging(sys.stderr, setStdout=False) 

    def print_results(results): 
     for name, (success, result) in zip(names, results): 
      if success: 
       print "%s -> %s" % (name, result) 
      else: 
       print >>sys.stderr, "error: %s failed. Reason: %s" % (
        name, result) 

    d = defer.DeferredList(map(client.getHostByName, names), consumeErrors=True) 
    d.addCallback(print_results) 
    d.addErrback(defer.logError) 
    d.addBoth(lambda _: reactor.stop()) 

reactor.callWhenRunning(process_names, """ 
    google.com 
    www.2eg11erdhrtj.com 
    www.e2ger2dh2rtj.com 
    www.eg2de3rh1rtj.com 
    www.ege2rh4rd1tj.com 
    www.ege52drhrtj1.com 
    """.split()) 
reactor.run()