【问题标题】:Performance Improvements with Processes or Threads [closed]进程或线程的性能改进[关闭]
【发布时间】:2014-05-25 17:13:31
【问题描述】:

我编写了一个从学校网站提取数据的脚本,但我在执行时间方面遇到了一些问题。

有 20 多个校区,每个校区都有三个学期的数据。该脚本查找这些学校名称,然后是每所学校可用的学期,然后是每学期提供课程的学科/部门。然后脚本搜索每个部门的课程,然后我用这些数据做事。

我只在一个校园内对脚本的执行进行了计时,它运行了三分钟多。当我为所有 24 个校区运行它时,它花了一个多小时。我正在使用“请求”库,它同步运行每个 HTTP 请求。我正在使用“请求”库,主要是因为它可以很好地处理会话。

我正在寻找减少脚本运行时间的方法,方法是让每个学期的各种请求并行运行。我怀疑如果我异步运行三个学期,那么每所学校应该花一分钟,而不是三分钟。然后,我可以并行运行所有学校,并为所有数据实现相同的分钟数。一分钟远小于一个小时零一刻钟!

  1. 我猜我错了吗,多线程/处理会如此大幅度地缩短执行时间?我应该为线程或进程使用哪些 Python 库?

  2. 一旦我在一个线程上处理了每所学校,如何将所有学校的数据整合到一个地方?我知道线程改变全局状态被认为是不好的做法,但是这里有什么替代方法?

【问题讨论】:

  • 不太了解 Python,但您所描述的正是最初发明线程的原因:即使在单处理器机器上,线程也是一种组织程序的方式,必须等待同时进行两件或多件事情(例如,在不同的套接字上等待两个或更多的 HTTP 回复)。
  • 注意,Python 线程不能使用多核。您可能仍然会看到它们的性能提升,但如果您的目标是同时运行多个事物,请查看可以利用多个内核的多处理。或者,其他 Python 实现,例如 Jython,可以在多个内核上运行多个线程。

标签: python multithreading performance multiprocessing


【解决方案1】:

1) 你没有错。将threading 库用于线程。对于进程,您可以使用multiprocessingos.forksubprocess,具体取决于您希望如何使用它们。

2) 谁说改变全局状态是不好的做法?这总是取决于上下文。显然,您必须以某种方式在线程之间共享数据结构。不过,您不必为此使用全局变量。例如:

from threading import Thread

def my_task(id, holder, some_other_args):
    # do something
    holder[id] = my_result

def main():
    total_data = {}
    threads = []
    for i in range(100):
        t = Thread(target=my_task, args=(i, total_data, ...))
        t.start()
        threads.append(t)

    for t in threads:
        t.join()

    print total_data  # <-- you have all results here

if __name__ == "__main__":
    main()

【讨论】:

    【解决方案2】:

    在 python 中,您需要多线程而不是多线程。由于 GIL,线程在 Python 中表现不佳。

    【讨论】:

      【解决方案3】:

      为什么要使用全局变量?与怪异的代码相同,但没有将全局变量传递给线程:

      #!/usr/bin/python3
      
      import threading
      
      class MyThread(threading.Thread):
          def __init__(self, target, name=None, args=(), kwargs={}):
              super().__init__(target=target, name=name, args=args, kwargs=kwargs)
              self.output = None
          def run(self):
              self.output = self._target(*self._args, **self._kwargs)
      
      
      def my_task(i):
          # do something
          return 'response ' + str(i)
      
      def main():
          total_data = list()
          threads = []
          for i in range(5):
              t = MyThread(target=my_task, args=[i,])
              t.start()
              threads.append(t)
      
          for t in threads:
              t.join()
              total_data.append(t.output)
      
          print(total_data)
      
      if __name__ == "__main__":
          main()
      

      输出是:

      Jean@MyDesktop:~$ ./test_threads.py 
      ['response 0', 'response 1', 'response 2', 'response 3', 'response 4']
      

      @yorodm:在这种情况下,我认为多线程应该就足够了,除非在本地对数据进行大量处理。

      【讨论】:

      • 不错。我正在使用 python 2。此外,我确实打算在掌握数据后对数据进行大量处理。
      猜你喜欢
      • 1970-01-01
      • 2016-03-23
      • 1970-01-01
      • 2011-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-27
      • 1970-01-01
      相关资源
      最近更新 更多