Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python MongoDB(PyMongo)多处理游标_Python_Multithreading_Mongodb_Multiprocessing - Fatal编程技术网

Python MongoDB(PyMongo)多处理游标

Python MongoDB(PyMongo)多处理游标,python,multithreading,mongodb,multiprocessing,Python,Multithreading,Mongodb,Multiprocessing,我正在尝试制作一个多处理MongoDB实用程序,它可以完美地工作,但我认为我有一个性能问题。。。即使有20名员工,它每秒处理的文档也不超过2800个。。。我想我可以快5倍。。。这是我的代码,它没有做任何异常,只是将剩余时间打印到光标的末尾 也许有更好的方法在MongoDB游标上执行多处理,因为我需要在每个具有1740万条记录集合的文档上运行一些东西,所以性能和更少的时间是必须的 START = time.time() def remaining_time(a, b): if START:

我正在尝试制作一个多处理MongoDB实用程序,它可以完美地工作,但我认为我有一个性能问题。。。即使有20名员工,它每秒处理的文档也不超过2800个。。。我想我可以快5倍。。。这是我的代码,它没有做任何异常,只是将剩余时间打印到光标的末尾

也许有更好的方法在MongoDB游标上执行多处理,因为我需要在每个具有1740万条记录集合的文档上运行一些东西,所以性能和更少的时间是必须的

START = time.time()
def remaining_time(a, b):
    if START:
        y = (time.time() - START)
        z = ((a * y) / b) - y
        d = time.strftime('%H:%M:%S', time.gmtime(z))
        e = round(b / y)
        progress("{0}/{1} | Tiempo restante {2} ({3}p/s)".format(b, a, d, e), b, a)


def progress(p, c, t):
    pc = (c * 100) / t
    sys.stdout.write("%s [%-20s] %d%%\r" % (p, '█' * (pc / 5), pc))
    sys.stdout.flush()

def dowork(queue):
    for p, i, pcount in iter(queue.get, 'STOP'):
        remaining_time(pcount, i)


def populate_jobs(queue):
    mongo_query = {}
    products = MONGO.mydb.items.find(mongo_query, no_cursor_timeout=True)
    if products:
        pcount = products.count()
        i = 1
        print "Procesando %s productos..." % pcount
        for p in products:
            try:
                queue.put((p, i, pcount))
                i += 1
            except Exception, e:
                utils.log(e)
                continue
    queue.put('STOP')


def main():
    queue = multiprocessing.Queue()

    procs = [multiprocessing.Process(target=dowork, args=(queue,)) for _ in range(CONFIG_POOL_SIZE)]

    for p in procs:
        p.start()

    populate_jobs(queue)

    for p in procs:
        p.join()
此外,我还注意到,大约每2500个aprox文档,脚本就会暂停大约.5-1秒,这显然是一个糟糕的问题。这是一个MongoDB问题,因为如果我执行完全相同的循环,但使用
范围(0,1000000)
脚本根本不会暂停,并以每秒57000次迭代的速度运行,总共需要20秒来结束脚本。。。与每秒2800个MongoDB文档有巨大差异

这是运行1000000迭代循环的代码

def populate_jobs(queue):
    mongo_query = {}
    products = MONGO.mydb.items.find(mongo_query, no_cursor_timeout=True)
    if products:
        pcount = 1000000
        i = 1
        print "Procesando %s productos..." % pcount
        for p in range(0, 1000000):
            queue.put((p, i, pcount))
            i += 1
    queue.put('STOP')
更新 正如我所看到的,问题不在于多处理本身,而是光标填充了未在多处理模式下运行的
队列
,这是一个填充
队列
的简单过程(
populateJobs
方法)也许如果我可以使游标多线程/多进程并并行填充
队列
,它的填充速度会更快,那么多处理方法
dowork
会更快,因为我认为有一个瓶颈,我每秒只在
队列中填充2800个项目,在
dowork
多进程中检索更多项目,但我不知道如何并行化
MongoDB
游标

也许,问题在于我的计算机和服务器的MongoDB之间的延迟。在我请求下一个游标和MongoDB告诉我下一个游标之间的延迟会将我的性能降低2000%(从61000 str/s降低到2800 doc/s)
没有我在本地主机MongoDB上尝试过,性能完全相同。。。这让我抓狂

为什么要使用多处理?您似乎没有在使用队列的其他线程中执行实际工作。Python有一个新的特性,它使多线程代码的性能低于您预期的性能。这可能会让这个程序变慢,而不是变快

以下是一些表演技巧:

  • 尝试在find()调用中将批大小设置为某个大数字(例如20000)。这是在客户端获取更多文档之前一次返回的最大文档数,默认值为101

  • 尝试将
    cursor\u type
    设置为,这可能会减少您看到的延迟


  • 以下是如何使用
    喂养孩子:

    START = time.time()
    def remaining_time(a, b):
        if START:
            y = (time.time() - START)
            z = ((a * y) / b) - y
            d = time.strftime('%H:%M:%S', time.gmtime(z))
            e = round(b / y)
            progress("{0}/{1} | Tiempo restante {2} ({3}p/s)".format(b, a, d, e), b, a)
    
    
    def progress(p, c, t):
        pc = (c * 100) / t
        sys.stdout.write("%s [%-20s] %d%%\r" % (p, '█' * (pc / 5), pc))
        sys.stdout.flush()
    
    def dowork(args):
        p, i, pcount  = args
        remaining_time(pcount, i)
    
    def main():
        queue = multiprocessing.Queue()
    
        procs = [multiprocessing.Process(target=dowork, args=(queue,)) for _ in range(CONFIG_POOL_SIZE)]
        pool = multiprocessing.Pool(CONFIG_POOL_SIZE)
        mongo_query = {}
        products = MONGO.mydb.items.find(mongo_query, no_cursor_timeout=True)
        pcount = products.count()
        pool.map(dowork, ((p, idx, pcount) for idx,p in enumerate(products)))
        pool.close()
        pool.join()
    
    请注意,使用
    pool.map
    需要立即将光标中的所有内容加载到内存中,这可能是一个问题,因为它有多大。您可以使用
    imap
    避免一次消耗整个内容,但需要指定
    chunksize
    以最小化IPC开销:

    # Calculate chunksize using same algorithm used internally by pool.map
    chunksize, extra = divmod(pcount, CONFIG_POOL_SIZE * 4)
    if extra:
       chunksize += 1
    
    pool.imap(dowork, ((p, idx, pcount) for idx,p in enumerate(products)), chunksize=chunksize)
    pool.close()
    pool.join()
    
    对于1000000个项目,chunksize为12500。您可以尝试更大和更小的尺寸,看看它如何影响性能


    如果瓶颈实际上只是从MongoDB中提取数据,我不确定这会有多大帮助。

    “我想我可以快5倍。”你为什么这么认为?因为我可以每秒向MongoDB执行8000次插入,这比简单的查找需要更多的努力,而且它每秒要执行2800个文档,所以我想我可以在find上获得更高的性能。您通过
    队列发送了多少个作业?如果是一个较大的数字,如果使用
    多处理.Pool
    ,可以在将作业发送到子进程之前对其进行批处理(假设您使用
    Pool.map
    将工作发送到子进程),则可以提高性能。如果要避免将整个任务列表存储在内存中,还可以将
    Pool.imap
    与相当大的
    chunksize
    一起使用。该数字是可变的,但肯定会超过1000000,查看我的上一次更新,因为速度问题在某种程度上point@dano我刚刚使用了一个
    multiprocesing.Pool
    async
    ,你能举一个例子来引用我问题中的代码吗?我对如何用这种方式给childs喂食有点迷茫..正如我所说,我在每个进程上都做了一些工作,但只是为了测试迭代的速度,我只是打印了一些统计数据,但真正的代码做了真正的工作。我试试你的建议。只是为了更新,我不是在做多线程,而是在做多处理,因为如果我want@noaGIL不适用于——如果我没有弄错你的说法,那就是你在尝试你的技巧后所暗示的,表现是一样的。我不明白为什么一个简单的范围循环是~61000个项目/秒,而游标是~2800个项目/秒……如果不迭代结果,您只从数据库加载第一批记录。显然,实际加载所有数据需要更长的时间。也就是说,为了得到一个更清晰的基准和更简单的测试用例,删除多处理的东西可能是值得的。使用你的方法,我可以获得每秒60000的速度,非常好。事实上,如果这个数字正确与否,我将进行更多的测试,但是有一个问题,使用你的方法,例如,我怎么能,在
    dowork
    内部更新一个数组,然后当
    i%n==0
    拉数组时(实际上我要在MongoDB上进行大容量插入),因为如果我使用
    多处理.Pool没有错,就不会调用n个进程,因此,
    dowork
    方法没有迭代任何东西,因此我可以推/拉到外部数组(迭代本身的外部)我希望我已经正确地解释了它,而且,这样,进程条信息不会显示有序的结果,它可以说
    392093/1000000=39%