簡體   English   中英

如何制作一個具有並行運行命令行工具功能的python模塊(不使用if __name__ =='__main__':因此可導入)?

[英]How to make a python module with function to run command line tools in parallel (w/o using if __name__ == '__main__': so it's importable)?

我想制作一個具有便利功能的python模塊,以便在Windows上使用Python 3.7並行運行命令。 (對於az cli命令)

我想要一個使該功能:

  • 易於使用:只需將命令列表作為字符串傳遞,並讓它們並行執行即可。
  • 讓我看看命令生成的輸出。
  • 在python庫中使用內置
  • 在Windows和Linux上同樣出色地工作(Python Multiprocessing使用fork(),而Windows沒有fork(),因此有時Multiprocessing代碼將在Linux上運行,但在Windows上不行。)
  • 可以制成可導入的模塊,以提供更大的便利。

這是出乎意料的困難,我認為以前在舊版本的python中是不可能的嗎? (我看到幾個2-8歲的問答,說if __name__==__main__:必須使用if __name__==__main__:進行並行處理,但是我發現在制作可導入模塊時,這種方法無法始終如一地可預測。

def removeExtraLinesFromString(inputstring):
    stringtoreturn = ""
    for line in inputstring.split("\n"):
        if len(line.strip()) > 0: #Only add non empty lines to the stringtoreturn
            stringtoreturn = stringtoreturn + line
    return stringtoreturn


def runCmd(cmd): #string of a command passed in here
    from subprocess import run, PIPE
    stringtoreturn = str( run(cmd, shell=True, stdout=PIPE).stdout.decode('utf-8') )
    stringtoreturn = removeExtraLinesFromString(stringtoreturn)
    return stringtoreturn


def exampleOfParrallelCommands():
    if __name__ == '__main__': #I don't like this method, because it doesn't work when imported, refractoring attempts lead to infinite loops and unexpected behavior.
        from multiprocessing import Pool
        cmd = "python -c \"import time;time.sleep(5);print('5 seconds have passed')\""
        cmds = []
        for i in range(12):  #If this were running in series it'd take at least a minute to sleep 5 seconds 12 times
            cmds.append(cmd)
        with Pool(processes=len(cmds)) as pool:
            results = pool.map(runCmd, cmds) #results is a list of cmd output
        print(results[0])
        print(results[1])
        return results

當我嘗試將其作為模塊導入時(由於使用if語句而導致無法正常運行),因此我嘗試重寫代碼以移動if語句,我想我刪除了它一次,這導致我的計算機進入循環直到我關閉程序。 __name__ == '__main__'我可以將模塊導入另一個python程序,但是要完成該工作,我必須添加__name__ == '__main__' ,這非常直觀。

我幾乎放棄了,但是經過兩天的大量python網站和SO帖子搜索后,我在這次問答中看到用戶jfs的代碼( Python:並行執行cat子進程 )后,終於找到了解決方法,我修改了他的代碼,最好適合我的問題的答案。

工具箱

def removeExtraLinesFromString(inputstring):
    stringtoreturn = ""
    for line in inputstring.split("\n"):
        if len(line.strip()) > 0: #Only add non empty lines to the stringtoreturn
            stringtoreturn = stringtoreturn + line
    return stringtoreturn


def runCmd(cmd): #string of a command passed in here
    from subprocess import run, PIPE
    stringtoreturn = str( run(cmd, shell=True, stdout=PIPE).stdout.decode('utf-8') )
    stringtoreturn = removeExtraLinesFromString(stringtoreturn)
    return stringtoreturn


def runParallelCmds(listofcommands): 
    from multiprocessing.dummy import Pool #thread pool
    from subprocess import Popen, PIPE, STDOUT
    listofprocesses = [Popen(listofcommands[i], shell=True,stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) for i in range(len(listofcommands))] 
    #Python calls this list comprehension, it's a way of making a list
    def get_outputs(process): #MultiProcess Thread Pooling require you to map to a function, thus defining a function.
        return process.communicate()[0] #process is object of type subprocess.Popen
    outputs = Pool(len(listofcommands)).map(get_outputs, listofprocesses) #outputs is a list of bytes (which is a type of string)
    listofoutputstrings = []
    for i in range( len(listofcommands) ):
        outputasstring = removeExtraLinesFromString(  outputs[i].decode('utf-8')  ) #.decode('utf-8') converts bytes to string
        listofoutputstrings.append( outputasstring )
    return listofoutputstrings

main.py

from toolbox import runCmd #(cmd)
from toolbox import runParallelCmds #(listofcommands)

listofcommands = []
cmd = "ping -n 2 localhost"
listofcommands.append(cmd)
cmd = "python -c \"import time;time.sleep(5);print('5 seconds have passed')\""
for i in range(12):
    listofcommands.append(cmd) # If 12 processes each sleep 5 seconds, this taking less than 1 minute proves parrallel processing

outputs = runParallelCmds(listofcommands)
print(outputs[0])
print(outputs[1])

輸出:

用32個字節的數據Ping neokylesPC [:: 1]:來自:: 1:time <1ms的響應來自:: 1:time <1ms對於:: 1的Ping統計信息:數據包:已發送= 2,已接收= 2,丟失= 0(損失0%),大約往返時間(以毫秒為單位):最小值= 0ms,最大值= 0ms,平均值= 0ms

5秒過去了

暫無
暫無

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

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