簡體   English   中英

具有共享變量(值)的Python多處理Pool.apply_async

[英]Python multiprocessing Pool.apply_async with shared variables (Value)

對於我的大學項目,我正在嘗試開發一個基於python的流量生成器。我在vmware上創建了2台CentOS計算機,我使用1個作為客戶端,使用1個作為服務器計算機。 我已經使用IP別名技術來增加客戶端的數量,並且僅使用一台客戶端/服務器計算機就可以進行服務。 到目前為止,我已經在客戶端計算機上創建了50個IP別名,並在服務器計算機上創建了10個IP別名。 我還使用多處理模塊來同時生成從所有50個客戶端到所有10個服務器的流量。 我還在服務器上(由於使用Apache Server,所以在/ var / www / html目錄中)開發了一些配置文件(1kb,10kb,50kb,100kb,500kb,1mb),並且我使用urllib2將請求從我的客戶端計算機。 我正在使用httplib + urllib2首先綁定到任何一個源別名IP,然后使用urllib2從該IP發送請求。 在這里,為了增加TCP連接數 ,我嘗試使用multiprocessing.Pool.apply_async模塊。 但是我在運行腳本時收到此錯誤“ RuntimeError:同步的對象僅應通過繼承在進程之間共享”。 經過一些調試后,我發現此錯誤是由於使用multiprocessing.Value引起的。 但是我想在進程之間共享一些變量,並且我還想增加TCP連接的數量。 在這里可以使用什么其他模塊(multiprocessing.Value除外)來共享一些公共變量? 否則此查詢還有其他解決方案嗎?

'''
Traffic Generator Script:

 Here I have used IP Aliasing to create multiple clients on single vm machine. 
 Same I have done on server side to create multiple servers. I have around 50 clients and 10 servers
'''
import multiprocessing
import urllib2
import random
import myurllist    #list of all destination urls for all 10 servers
import time
import socbindtry   #script that binds various virtual/aliased client ips to the script
m=multiprocessing.Manager()
response_time=m.list()    #some shared variables
error_count=multiprocessing.Value('i',0)
def send_request3():    #function to send requests from alias client ip 1
    opener=urllib2.build_opener(socbindtry.BindableHTTPHandler3)    #bind to alias client ip1
    try:
        tstart=time.time()
        for i in range(myurllist.url):
            x=random.choice(myurllist.url[i])
            opener.open(x).read()
            print "file downloaded:",x
            response_time.append(time.time()-tstart)
    except urllib2.URLError, e:
        error_count.value=error_count.value+1
def send_request4():    #function to send requests from alias client ip 2
    opener=urllib2.build_opener(socbindtry.BindableHTTPHandler4)    #bind to alias client ip2
    try:
        tstart=time.time()
        for i in range(myurllist.url):
            x=random.choice(myurllist.url[i])
            opener.open(x).read()
            print "file downloaded:",x
            response_time.append(time.time()-tstart)
    except urllib2.URLError, e:
        error_count.value=error_count.value+1
#50 such functions are defined here for 50 clients
def func():
    pool=multiprocessing.Pool(processes=750)
    for i in range(5):
        pool.apply_async(send_request3)
        pool.apply_async(send_request4)
        pool.apply_async(send_request5)
#append 50 functions here
    pool.close()
    pool.join()
    print"All work Done..!!"
    return
start=float(time.time())
func()
end=float(time.time())-start
print end

如錯誤消息所述,您不能通過pickle傳遞multiprocessing.Value 但是,您可以使用multiprocessing.Manager().Value

import multiprocessing
import urllib2
import random
import myurllist    #list of all destination urls for all 10 servers
import time
import socbindtry   #script that binds various virtual/aliased client ips to the script

def send_request3(response_time, error_count):    #function to send requests from alias client ip 1
    opener=urllib2.build_opener(socbindtry.BindableHTTPHandler3)    #bind to alias client ip1
    try:
        tstart=time.time()
        for i in range(myurllist.url):
            x=random.choice(myurllist.url[i])
            opener.open(x).read()
            print "file downloaded:",x
            response_time.append(time.time()-tstart)
    except urllib2.URLError, e:
        with error_count.get_lock():
            error_count.value += 1

def send_request4(response_time, error_count):    #function to send requests from alias client ip 2
    opener=urllib2.build_opener(socbindtry.BindableHTTPHandler4)    #bind to alias client ip2
    try:
        tstart=time.time()
        for i in range(myurllist.url):
            x=random.choice(myurllist.url[i])
            opener.open(x).read()
            print "file downloaded:",x
            response_time.append(time.time()-tstart)
    except urllib2.URLError, e:
        with error_count.get_lock():
            error_count.value += 1

#50 such functions are defined here for 50 clients

def func(response_time, error_count):
    pool=multiprocessing.Pool(processes=2*multiprocessing.cpu_count())
    args = (response_time, error_count)
    for i in range(5):
        pool.apply_async(send_request3, args=args)
        pool.apply_async(send_request4, args=args)
#append 50 functions here
    pool.close()
    pool.join()
    print"All work Done..!!"
    return

if __name__ == "__main__":
    m=multiprocessing.Manager()
    response_time=m.list()    #some shared variables
    error_count=m.Value('i',0)

    start=float(time.time())
    func(response_time, error_count)
    end=float(time.time())-start
    print end

其他一些注意事項:

  1. 使用具有750個進程的Pool不是一個好主意。 除非您使用具有數百個CPU內核的服務器,否則這將使您的計算機不堪重負。 這樣可以更快,更省力地使用更少的進程。 更像2 * multiprocessing.cpu_count()
  2. 最佳做法是,應將需要使用的所有共享參數明確傳遞給子進程,而不要使用全局變量。 這增加了在Windows上運行代碼的機會。
  3. 看起來您的所有send_request*函數幾乎都做同樣的事情。 為什么不只做一個函數並使用變量來決定使用哪個socbindtry.BindableHTTPHandler 這樣可以避免大量的代碼重復。
  4. 您增加error_count方式不是進程/線程安全的,並且容易受到競爭條件的影響。 您需要使用鎖來保護增量(就像我在上面的示例代碼中所做的那樣)。

可能是因為Python多進程在Windows和Linux之間存在差異 (我很認真,不知道多進程在VM中的工作方式,在這里就是這種情況。)

這可能有效;

import multiprocessing
import random
import myurllist    #list of all destination urls for all 10 servers
import time

def send_request3(response_time, error_count):    #function to send requests from alias client ip 1
    opener=urllib2.build_opener(socbindtry.BindableHTTPHandler3)    #bind to alias client ip1
    try:
        tstart=time.time()
        for i in range(myurllist.url):
            x=random.choice(myurllist.url[i])
            opener.open(x).read()
            print "file downloaded:",x
            response_time.append(time.time()-tstart)
    except urllib2.URLError, e:
        error_count.value=error_count.value+1
def send_request4(response_time, error_count):    #function to send requests from alias client ip 2
    opener=urllib2.build_opener(socbindtry.BindableHTTPHandler4)    #bind to alias client ip2
    try:
        tstart=time.time()
        for i in range(myurllist.url):
            x=random.choice(myurllist.url[i])
            opener.open(x).read()
            print "file downloaded:",x
            response_time.append(time.time()-tstart)
    except urllib2.URLError, e:
        error_count.value=error_count.value+1
#50 such functions are defined here for 50 clients
def func():
    m=multiprocessing.Manager()
    response_time=m.list()    #some shared variables
    error_count=multiprocessing.Value('i',0)

    pool=multiprocessing.Pool(processes=750)
    for i in range(5):
        pool.apply_async(send_request3, [response_time, error_count])
        pool.apply_async(send_request4, [response_time, error_count])
        # pool.apply_async(send_request5)
#append 50 functions here
    pool.close()
    pool.join()
    print"All work Done..!!"
    return


start=float(time.time())
func()
end=float(time.time())-start
print end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM