RF可用的多線程裝飾器

RF本身沒有多線程的庫,我們可以使用類似下面的方法,並對外公開parseArgmultipleArg兩個方法(寫到測試類裏面),給需要併發的函數套上裝飾器,即可實現多線程執行函數。由於可以只傳單個的參數,因此並不影響函數的單線程運行。
比如在RIDE/RED內可以寫成這樣的調用

${arg1} parseArg mi
${arg2} parseArg 故宮喵
log many baidusearch ${arg1} ${arg2}
# coding: utf-8
from threading import Thread
# resset=[]  # 儲存線程函數返回值的列表,這一句其實可以不要,因爲在multiThread開啓的時候會自動在外部創建全局變量resset爲[](假如resset不存在,否則即賦值)

def getResult(func):  # 重定向函數返回的結果
    def infunc(*args,**kwargs):
        args=list(args)
        tid=args.pop()  # 去掉最後一個代表線程編號的參數
        args=tuple(args)
        try:
            resset.append((func(*args,**kwargs),tid))  # 結果是一個由二元元組組成的列表,每個線程一個元組,元組內第一個元素是線程運行的結果,第二個是線程編號
        except Exception,e:
            resset.append((e,tid))  # 如果線程內報錯,就返回錯誤對象
    return infunc

def multiThread(func):  # 實現多線程
    def infunc(*args):
        global resset
        resset=[] # 每次調用前,清除結果集
        tli=[]  # 線程對象列表
        tid=0  # 初始線程編號
        for arg in args:  # 處理傳入的參數列表
            if len(arg)==1:
                if type(arg[0])==type({}):
                    targ=()  # 設置位置參數
                    darg=arg[0]  # 設置命名參數
                else:
                    targ=arg[0]
                    darg={}
            elif len(arg)==0 or arg==None:
                targ=()
                darg={}
            else:
                targ=arg[0]  # (args,kwargs) [0]
                darg=arg[1]  # (args,kwargs) [1]
            try:
                assert type(targ)==type(()) and type(darg)==type({})  # 確定傳來的參數格式正確
            except:
                raise ValueError, 'arguement format error'
            targ=tuple(list(targ)+[tid])  # 在位置參數的最後一個位置,加上線程編號傳進去。getResult裏會把這個參數pop掉,並記錄到結果裏
            tli.append(Thread(target=func,args=targ,kwargs=darg))  # 線程列表填充
            tid=tid+1  # 線程編號遞增
        for th in tli:
            th.setDaemon(True)
            th.start()
        for th in tli:
            th.join()  # 大家都開始了才join阻塞
        return {x[1]:x[0] for x in resset}  # 結果字典,resset的結果是二元元組,0號元素是函數返回值,1號元素是線程編號tid

    return infunc

def parseArg(*args,**kwargs): # 打包單個線程的參數
    return (args,kwargs)

def multipleArg(gtuple,times): # 複製某個線程的參數n次,形成參數元組
    return (gtuple,)*times

####################################### 分割線,下爲演示部分 #######################################

from selenium import webdriver
import time, re

@multiThread
@getResult
def baidusearch(statement):
    driver=webdriver.Chrome()
    driver.get(r'http://www.baidu.com')
    driver.maximize_window()
    driver.implicitly_wait(10)
    kw=driver.find_element_by_id('kw')
    kw.clear()
    kw.send_keys(statement)
    driver.find_element_by_id('su').click()
    time.sleep(2)
    resNumber=driver.find_element_by_xpath("//span[@class='nums_text']").text
    resNumber=re.findall('[0-9,]+',resNumber)[0]
    driver.close()
    return resNumber

li1=parseArg('mi')
li2=parseArg('wo')
li3=parseArg(u'故宮喵')
print(baidusearch(li1,li2,li3))

lis=multipleArg(parseArg('python'),3) # 或者可以像下面這樣,連續生成多個同樣的關鍵字
print(baidusearch(*lis))  # 這種方式不要忘記解包

lit=tuple([ parseArg('html'+str(x)) for x in range(1,6) ])  # 使用推導式,分別搜索html1 html2 ... html5
print(baidusearch(*lit))

################################# 可以使用路由的方式,讓不同的函數併發執行 #######################

def plus(x,y):
    return x+y

def minus(x,y):
    return abs(x-y)

@multiThread
@getResult
def union(func_name,*args,**kwargs):  # 可以用這種方法來實現路由,讓不同的函數同時執行在一個線程裏
    return eval(func_name)(*args,**kwargs)

li1=parseArg('plus',1,2)
li2=parseArg('minus',3,y=5)
li3=parseArg('plus',x=4,y=6)
print(union(li1,li2,li3))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章