2013-01-08 18 views
13

ftpディレクトリ全体を並行してダウンロードしようとしています。Pythonマルチプロセッシング:TypeError:予期される文字列またはUnicodeオブジェクト、NoneTypeが見つかりました

#!/usr/bin/python 
import sys 
import datetime 
import os 
from multiprocessing import Process, Pool 
from ftplib import FTP 
curYear="" 
remotePath ="" 
localPath = "" 

def downloadFiles (remotePath,localPath): 
     splitted = remotePath.split('/'); 
     host= splitted[2] 
     path='/'+'/'.join(splitted[3:]) 
     ftp = FTP(host) 
     ftp.login() 
     ftp.cwd(path) 
     filenames = ftp.nlst() 
     total=len(filenames) 
     i=0 
     pool = Pool() 
     for filename in filenames: 
         local_filename = os.path.join(localPath,filename) 
         pool.apply_async(downloadFile, (filename,local_filename,ftp)) 
         #downloadFile(filename,local_filename,ftp); 
         i=i+1 

     pool.close() 
     pool.join() 
     ftp.close() 

def downloadFile(filename,local_filename,ftp): 
     file = open(local_filename, 'wb') 
     ftp.retrbinary('RETR '+ filename, file.write) 
     file.close() 

def getYearFromArgs(): 
     if len(sys.argv) >= 2 and sys.argv[1] == "Y": 
       year = sys.argv[2] 
       del sys.argv[1:2] 
     else: 
       year = str(datetime.datetime.now().year) 
     return year 

def assignGlobals(): 
     global p 
     global remotePath 
     global localPath 
     global URL 
     global host 
     global user 
     global password 
     global sqldb 
     remotePath = 'ftp://ftp3.ncdc.noaa.gov/pub/data/noaa/isd-lite/%s/' % (curYear) 
     localPath = '/home/isd-lite/%s/' % (curYear) 

def main(): 
     global curYear 
     curYear=getYearFromArgs() 
     assignGlobals() 
     downloadFiles(remotePath,localPath) 

if __name__ == "__main__": 
     main() 

しかし、私はこの例外を取得:

Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/usr/lib64/python2.6/threading.py", line 532, in __bootstrap_inner 
    self.run() 
    File "/usr/lib64/python2.6/threading.py", line 484, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "/usr/lib64/python2.6/multiprocessing/pool.py", line 225, in _handle_tasks 
    put(task) 
TypeError: expected string or Unicode object, NoneType found 

私は、この行コメントアウトした場合:

pool.apply_async(downloadFile, (filename,local_filename,ftp) 

をし、この行のコメント削除:次に

downloadFile(filename,local_filename,ftp); 

をそれはうまく動作しますが、それは遅くていないマルチスレッド化。

+0

このコードは書かれたとおりに動作しません( 'downloadFiles'には変数名のエラーがあります)。作業コードを投稿し、問題を示す 'downloadFiles'のサンプルコールを表示できますか? –

+0

申し訳ありません - 私は自分の投稿を改訂しました。 –

+0

try: 'from multiprocessing.dummy import Pool'。プロセスの代わりにスレッドを使用します。問題が初期化されているか、いくつかのオブジェクト、例えば' ftp'を子プロセスに渡している可能性があります。 'multiprocessing'のこのバージョンが間違って報告する場合に例外を記録する' try/except'ブロックに 'downloadFile()'本文をラップしてください。 – jfs

答えて

-1

は、あなたが試してみました:

pool.apply_async(downloadFile, args=(filename,local_filename,ftp)) 

をプロトタイプは次のとおりです。

apply_async(func, args=(), kwds={}, callback=None) 
18

アップデート、2014年5月9日:

私は正確な制限を決定しました。 Python's pickle facilityでオブジェクトを節約することができる限り、プロセス境界を越えてワーカープロセスにオブジェクトを送信することは可能です。私が元の回答で述べた問題は、私が作業員にファイルハンドルを送信しようとしていたために発生しました。これが動作しない理由を迅速実験は:

したがって
>>> f = open("/dev/null") 
>>> import pickle 
>>> pickle.dumps(f) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python2.7/pickle.py", line 1374, in dumps 
    Pickler(file, protocol).dump(obj) 
    File "/usr/lib/python2.7/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/usr/lib/python2.7/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/usr/lib/python2.7/copy_reg.py", line 70, in _reduce_ex 
    raise TypeError, "can't pickle %s objects" % base.__name__ 
TypeError: can't pickle file objects 

、あなたはプロセスの境界を越えて送信しているすべてのものを確認して、このスタックオーバーフローの問題を見つけるためにあなたを導いたPythonのエラーが発生している場合ピックアップすることができます。

オリジナルの答え:

私は少し遅れて応答しますよ。しかし、私はPythonのマルチプロセッシングモジュールを使用しようとしている間も、元のポスターと同じエラーメッセージを出しました。私はこのスレッドにつまずく他の誰かが試してみるように私の発見を記録します。

私の場合、エラーは私がワーカーのプールに送信しようとしていたために発生しました。私は、プールワーカーが噛むためにファイルオブジェクトの配列を渡そうとしていました。それは明らかにPythonのプロセス境界を越えて送信するにはあまりにも多くのことです。私は、入力と出力ファイル名の文字列を指定したプールワーカー辞書を送信することで問題を解決しました。

だから、(私がmap()imap_unordered()を使用)このようなapply_asyncとして関数に渡すことを反復可能に「などの長い値が上がらないよう(数値や文字列のリスト、あるいは詳細な辞書データ構造を含めることができるようですt個のオブジェクト)。あなたのケースでは

pool.apply_async(downloadFile, (filename,local_filename,ftp)) 

ftpが問題を引き起こしている可能性がありますオブジェクトです。回避策として、作業者にパラメータを送信することを推奨します(この場合はhostpathのようになります)。ワーカーがオブジェクトをインスタンス化し、クリーンアップを処理できるようにします。

+0

あなたは真剣にオブジェクトをマルチプロセッシング機能にマップできませんか? – CornSmith

+0

正確な制限は何か分かりません。私が説明したのは、私の問題を解決したものです。 –

+0

そうですね、あなたと同じように(私はスレッドを代わりに使用してしまっただけで)やり遂げなければなりませんでした。この制限はGILのためですか? Pythonがスレッドセーフであれば、これを行うことができると思います。 – CornSmith

関連する問題