【问题标题】:subprocess.Popen in Threads线程中的 subprocess.Popen
【发布时间】:2013-03-17 22:21:16
【问题描述】:

我有许多文件(超过 4000 个)要同时加载到 PostgreSQL 中。我已将它们分成 4 个不同的文件列表,我希望有一个线程遍历每个列表来加载数据。

我遇到的问题是我使用 os.system 来调用加载程序,但这会阻止其他线程同时运行。如果我使用 subprocess.Popen,那么它们会同时运行,但线程认为它们已完成执行,因此请转到我脚本的下一部分。

我这样做是否正确?或者有没有更好的方法从线程中调用子进程。

def thread1Load(self, thread1fileList):
    connectionstring = settings.connectionstring
    postgreshost = settings.postgreshost
    postgresdatabase = settings.postgresdatabase
    postgresport = settings.postgresport
    postgresusername = settings.postgresusername
    postgrespassword = settings.postgrespassword

    tablename = None
    encoding = None
    connection = psycopg2.connect(connectionstring)

    for filename in thread1fileList:
        load_cmd = #load command
        run = subprocess.Popen(load_cmd, shell=True)
    print "finished loading thread 1"


def thread2Load(self, thread2fileList):
    connectionstring = settings.connectionstring
    postgreshost = settings.postgreshost
    postgresdatabase = settings.postgresdatabase
    postgresport = settings.postgresport
    postgresusername = settings.postgresusername
    postgrespassword = settings.postgrespassword

    tablename = None

    connection = psycopg2.connect(connectionstring)
    for filename in thread2fileList:
        load_cmd = #load command            
        run = subprocess.Popen(load_cmd, shell=True)
    print "finished loading thread 2"


def thread3Load(self, thread3fileList):
    connectionstring = settings.connectionstring
    postgreshost = settings.postgreshost
    postgresdatabase = settings.postgresdatabase
    postgresport = settings.postgresport
    postgresusername = settings.postgresusername
    postgrespassword = settings.postgrespassword

    tablename = None
    connection = psycopg2.connect(connectionstring)

    for shapefilename in thread3fileList:
        load_cmd = #load command
        run = subprocess.Popen(load_cmd, shell=True)
    print "finished loading thread 3"

def thread4Load(self, thread4fileList):
    connectionstring = settings.connectionstring
    postgreshost = settings.postgreshost
    postgresdatabase = settings.postgresdatabase
    postgresport = settings.postgresport
    postgresusername = settings.postgresusername
    postgrespassword = settings.postgrespassword

    tablename = None

    connection = psycopg2.connect(connectionstring)

    for filename in thread4fileList:
        load_cmd = #load command
        run = subprocess.Popen(load_cmd, shell=True)

    print "finished loading thread 4"


def finishUp(self):
    print 'finishing up'


def main():
load = Loader()

thread1 = threading.Thread(target=(load.thread1Load), args=(thread1fileList, ))
thread2 = threading.Thread(target=(load.thread2Load), args=(thread2fileList, ))
thread3 = threading.Thread(target=(load.thread3Load), args=(thread3fileList, ))
thread4 = threading.Thread(target=(load.thread4Load), args=(thread4fileList, ))
threads = [thread1, thread2, thread3, thread4]
for thread in threads:
    thread.start()
    thread.join()


load.finishUp(connectionstring)

if __name__ == '__main__':
main()

【问题讨论】:

    标签: python multithreading subprocess


    【解决方案1】:
    • Don't repeat yourself。一种threadLoad 方法就足够了。这样,如果您需要修改方法中的某些内容,则无需在 4 个不同的地方进行相同的修改。
    • 使用run.communicate() 阻塞直到子进程完成。
    • 这会启动一个线程,然后阻塞直到该线程完成,然后 启动另一个线程等:

      for thread in threads:
          thread.start()
          thread.join()
      

      相反,先启动所有线程,然后加入所有线程:

      for thread in threads:
          thread.start()
      for thread in threads:
          thread.join()
      

    import subprocess
    import threading
    
    
    class Loader(object):
        def threadLoad(self, threadfileList):
            connectionstring = settings.connectionstring
            ...
            connection = psycopg2.connect(connectionstring)
    
            for filename in threadfileList:
                load_cmd =  # load command
                run = subprocess.Popen(load_cmd, shell=True)
                # block until subprocess is done
                run.communicate()
            name = threading.current_thread().name
            print "finished loading {n}".format(n=name)
    
        def finishUp(self):
            print 'finishing up'
    
    
    def main():
        load = Loader()
        threads = [threading.Thread(target=load.threadLoad, args=(fileList, ))
                   for fileList in (thread1fileList, thread2fileList,
                                    thread3fileList, thread4fileList)]
        for thread in threads:
            thread.start()
        for thread in threads:
            thread.join()
    
        load.finishUp(connectionstring)
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-02
      • 2010-12-29
      • 2014-02-07
      • 1970-01-01
      • 2020-10-02
      • 2014-12-02
      • 1970-01-01
      相关资源
      最近更新 更多