【问题标题】:Python threading help NeededPython 线程帮助 需要
【发布时间】:2015-09-29 02:13:06
【问题描述】:

看到不完全适合我的案例的例子,我是雪盲的......或者他们可能这样做。因此,如果有很好的例子,我无法用大约 3 周的 Python 经验来解释它们

我有一个脚本可以查询数据库,收集可下载电影的列表,然后将它们逐一下载到您选择的目录。而且我想让它一次下载 4 或 5 个,因为这样做需要很长时间。

这是我尝试做的简化版本,myapp 是我的数据库应用程序。然而,它似乎只是按顺序运行,即使它说它正在启动两个线程

listOfIDs 是一些容器的 id,可能有也可能没有电影,然后 versionS 返回电影文件名。

import threading
import myapp_api

listOfIDs = (14809, 14808, 14807, 14806, 14805, 14804, 14803)
for ID in listOfIDs:
    versionS = myapp.find_one('Version', [['id', 'is', ID]], ['uploaded_movie'])

ipath = ('/Users/me/Desktop/scripts/downloads/')

exitFlag = 0

class myThread (threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter
    def run(self):
        print "Starting " + self.name
        for ID in listOfIDs:
            print "\nID= " + str(ID) + "\n"
            downLoad(ID)
        print "Exiting " + self.name

def downLoad(ID):
    versionS = myapp.find_one('Version', [['id', 'is', ID]], ['uploaded_movie'])
    path = ipath + (str(versionS).split("'")[5])
    result = myapp.download_attachment(attachment=versionS['uploaded_movie'], file_path=path)
    print "Thread Name = " + threadName


# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)


# Start new Threads
thread1.start()
thread2.start()

print "Exiting Main Thread"

好的,所以我修改了代码以接受ShadowRanger 的建议,但它仍然只是一次下载一个,我把它塞到某个地方了吗? ...代码现在看起来像这样。

import threading
import myapp_api
from collections import deque

listOfIDs = (14809, 14808, 14807, 14806, 14805, 14804, 14803)
for ID in listOfIDs:
    versionS = myapp.find_one('Version', [['id', 'is', ID]], ['uploaded_movie'])

ipath = ('/Users/me/Desktop/scripts/downloads/')

def downLoad(ID):
    path = ipath + (str(versionS).split("'")[5])
    result = myapp.download_attachment(attachment=versionS['uploaded_movie'], file_path=path)

with closing(multiprocessing.Pool(4)) as pool:
    deque(pool.imap_unordered(downLoad, listOfIDs), maxlen=0)

最后,ShadowRanger 的所有建议都是正确的,错误在于我做错了(我想我很早就迭代了 listOfIDs,并且只将最后一个传递给函数).. . 这是最终的工作版本。

   import threading
    import myapp_api
    from collections import deque

listOfIDs = (14809, 14808, 14807, 14806, 14805, 14804, 14803)

ipath = ('/Users/me/Desktop/scripts/downloads/')

def downLoad(ID):
    versionS = myapp.find_one('Version', [['id', 'is', ID]], ['uploaded_movie'])
    path = ipath + (str(versionS).split("'")[5])
    result = myapp.download_attachment(attachment=versionS['uploaded_movie'], file_path=path)


with closing(multiprocessing.Pool(4)) as pool:
    deque(pool.imap_unordered(downLoad, listOfIDs), maxlen=0)

【问题讨论】:

  • 如果有问题的代码委托给在 Python 中实现的模块,GIL 将导致线程问题。通常,像 DB 访问这样的 I/O 绑定的东西会在阻塞等待结果的同时释放 GIL,但我不知道你正在使用什么库。就此而言,如果库在内部锁定,那将使线程无用。
  • 有没有一种简单的方法来判断我是否因为这些其他库在内部锁定而获得 GIL
  • GIL 和库内部锁定是完全分开的。将import multiprocessing.dummy as multiprocessing 改回import multiprocessing(因此您运行单独的进程,而不是线程)将在很大程度上删除 GIL(就此而言,可能会避免库锁定),但会增加进程间通信的开销。跨度>

标签: python multithreading


【解决方案1】:

我看不到线程是如何拆分工作的。看起来他们都下载了同一套东西。

如果目标是根据已知 ID 下载一堆文件,multiprocessing 有一个 .dummy 模块,它可以像 multiprocessing 一样工作,但使用线程实现,这为您提供了一个简单的线程池:

import multiprocessing.dummy as multiprocessing
from contextlib import closing

with closing(multiprocessing.Pool(4)) as pool: # Pick your favorite number of workers
    pool.map(downLoad, listOfIDs)

【讨论】:

  • pool.map 返回由map-ed 函数返回的值列表,在本例中为downLoad;因为它没有return 语句,所以它创建(然后立即丢弃)Nones 的列表。在大多数情况下没什么大不了的,但是如果您的列表很大,您可以通过添加 from collections import deque 的导入并将 pool.map 行更改为 deque(pool.imap_unordered(downLoad, listOfIDs), maxlen=0) 来避免不必要的浪费,从而避免不必要地存储返回值 (@987654335 @ 和 maxlen=0 是运行迭代器以耗尽、丢弃结果的最有效方式。
  • 我现在已经将这个示例逐行放入我的“实际”脚本中,并且每次都会使 python 崩溃。 ...我已经检查了在主脚本中输入的内容与我在测试中硬编码的内容相同,并且所有内容都已签出。我在 Mac 上执行此操作,出现的崩溃报告提到 crashed on child side of fork pre-exec ......所以我想知道我可以在哪里更深入地挖掘......抛出 dig() 清楚地显示了更多的 vars 在主要浮动脚本,但我不确定它们中的哪一个(如果有的话)可能对此产生不利影响。
  • 这看起来像你的问题? blog.yimingliu.com/2015/07/22/… 还是这个? github.com/matplotlib/matplotlib/issues/2902 看起来 Python 的 Mac 版本已经出现了一些重复的问题。
  • 看起来,是的,我刚刚在 Linux 上运行了问题脚本,没有问题,它运行了众所周知的烫伤猫……没有报告任何错误。我会尝试修复它,但知道实际错误是什么,这很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多