2016-10-01 11 views
2

私はPythonリクエストでアクションを起こそうとしています。ここに私のコードです:Python、リクエスト、スレッディング、どのくらい速くPythonリクエストがソケットを閉じますか?

import threading 
import resource 
import time 
import sys 

#maximum Open File Limit for thread limiter. 
maxOpenFileLimit = resource.getrlimit(resource.RLIMIT_NOFILE)[0] # For example, it shows 50. 

# Will use one session for every Thread. 
requestSessions = requests.Session() 
# Making requests Pool bigger to prevent [Errno -3] when socket stacked in CLOSE_WAIT status. 
adapter = requests.adapters.HTTPAdapter(pool_maxsize=(maxOpenFileLimit+100)) 
requestSessions.mount('http://', adapter) 
requestSessions.mount('https://', adapter) 

def threadAction(a1, a2): 
    global number 
    time.sleep(1) # My actions with Requests for each thread. 
    print number = number + 1 

number = 0 # Count of complete actions 

ThreadActions = [] # Action tasks. 
for i in range(50): # I have 50 websites I need to do in parallel threads. 
    a1 = i 
    for n in range(10): # Every website I need to do in 3 threads 
     a2 = n 
     ThreadActions.append(threading.Thread(target=threadAction, args=(a1,a2))) 


for item in ThreadActions: 
    # But I can't do more than 50 Threads at once, because of maxOpenFileLimit. 
    while True: 
     # Thread limiter, analogue of BoundedSemaphore. 
     if (int(threading.activeCount()) < threadLimiter): 
      item.start() 
      break 
     else: 
      continue 

for item in ThreadActions: 
    item.join() 

しかし、事は、私は50個のスレッドを立ち上げた後、Thread limiterはその作業を完了するために、いくつかのスレッドを待つし始めていることです。そして、ここに問題があります。 scritがリミッターに行った後、lsof -i|grep python|wc -lは50以上のアクティブな接続を示しています。しかし、Limiterの前には、すべて< = 50のプロセスが示されていました。なぜこうなった?または、すでにソケットを使用しているのを防ぐために、requests.sclone()の代わりにrequests.session()を使用する必要がありますか?

+0

スレッドリミッタはタイトなループに入り、処理時間の大半を占めます。それを遅くするために 'sleep(.1)'のようなものを試してみてください。さらに、50個のリクエストに制限されたキューを使用し、それらのスレッドにスレッドを読み込ませるようにしてください。 – tdelaney

+0

あなたのユーザーのためのOSの制限を増やすことで[ulimit](http://stackoverflow.com/questions/6774724/why-python-has-limit-for-count-of-filehandles)と[fs .file-max](https://cs.uwaterloo.ca/~brecht/servers/openfiles.html)。それを行った後、内部のpythonからの制限を増やして、[setrlimit](https://coderwall.com/p/ptq7rw/increase-open-files-limit-and-drop-privileges-in-python)を探します。もちろん、busy-while-loopsを不必要に実行しておらず、コードを適切に多重化していることを確認してください。 – blackpen

+0

はい、私は理解し、実際のスクリプトではBoundedSemaphoreを使用します。しかし、 'lsof -i | grep python | wc -l'は、スクリプトが限界に達した直後にはるかに低い数値を表示するのはなぜですか? – passwd

答えて

1

リミッタは処理時間の大部分を占めるタイトなループです。スレッドプールを使用して、代わりにワーカーの数を制限します。

import multiprocessing.pool 

# Will use one session for every Thread. 
requestSessions = requests.Session() 
# Making requests Pool bigger to prevent [Errno -3] when socket stacked in CLOSE_WAIT status. 
adapter = requests.adapters.HTTPAdapter(pool_maxsize=(maxOpenFileLimit+100)) 
requestSessions.mount('http://', adapter) 
requestSessions.mount('https://', adapter) 

def threadAction(a1, a2): 
    global number 
    time.sleep(1) # My actions with Requests for each thread. 
    print number = number + 1 # DEBUG: This doesn't update number and wouldn't be 
           # thread safe if it did 

number = 0 # Count of complete actions 

pool = multiprocessing.pool.ThreadPool(50, chunksize=1) 

ThreadActions = [] # Action tasks. 
for i in range(50): # I have 50 websites I need to do in parallel threads. 
    a1 = i 
    for n in range(10): # Every website I need to do in 3 threads 
     a2 = n 
     ThreadActions.append((a1,a2)) 

pool.map(ThreadActons) 
pool.close() 
+0

マルチスレッドはスレッド化より速く動作しますか?これがどのようにプロセッサの負荷に影響しますか? – passwd

+0

それはトレードオフです...そして、LinuxよりもWindowsでは違います。マルチプロセッシングでは、親と子の間でデータをシリアライズする必要があります(通常、ウィンドウでは、親が親メモリ空間のクローンを取得しないため、より多くのコンテキストをシリアライズする必要があります)。 GIL。より高いCPUおよび/またはより低いデータオーバーヘッドは、マルチプロセッシングを良好にする。しかし、ほとんどがI/Oバウンドの場合、スレッドプールは問題ありません。 – tdelaney

関連する問題