并行处理庞大的列表

时间:2015-09-02 09:15:54

标签: python multithreading list

我需要从存储在.txt文件中的域(大约50 MB大小)进行大量网页编写。

我想做多线程。因此,我将一些条目加载到Python列表中,并使用线程处理每个条目。

示例:

biglist = ['google.com','facebook.com','apple.com']
threads = [threading.Thread(target=fetch_url, args=(chuck,)) 
           for domain in biglist]
for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

它可以工作,但在我看来,它不是很有效,因为有大量的内存使用,而且需要很长时间才能完成。

有什么更好的方法来实现我的目标?

3 个答案:

答案 0 :(得分:0)

您使用的是错误的库。 threading.Thread并没有真正受益于多个处理器,因为它被Global Interpreter Lock阻止。

来自threading模块(c.f.)的文档:

  

CPython实现细节:在CPython中,由于全局解释器锁,只有一个线程可以同时执行Python代码(即使某些面向性能的库可能会克服这个限制)。如果您希望应用程序更好地利用多核计算机的计算资源,建议您使用multiprocessing。但是,如果要同时运行多个I / O绑定任务,threading仍然是一个合适的模型。

我建议您使用process pool模块中的multiprocessingmap()来并行计算结果。使用比处理器更多的进程没有任何意义。

来自multiprocessing模块(c.f.)的文档:

  

multiprocessing是一个使用类似于threading模块的API支持产生进程的包。 multiprocessing包提供本地和远程并发,通过使用子进程而不是线程有效地侧面执行全局解释器锁。因此,multiprocessing模块允许程序员充分利用给定计算机上的多个处理器。它可以在Unix和Windows上运行。

示例:

from multiprocessing import Pool

number_of_processors = 3

data = range(10)

def func(x):
    print "processing", x
    return x*x

pool = Pool(number_of_processors)
ret = pool.map(func, data)

输出结果为:

$ python test.py
processing 0
processing 1
processing 3
processing 2
processing 4
processing 5
processing 6
processing 7
processing 8
processing 9
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

答案 1 :(得分:0)

不要使用列表/线程,而是使用队列/进程 如果你知道Redis我建议RQ(http://python-rq.org) - 我做同样的事情并且工作得非常好。

答案 2 :(得分:0)

添加到moooeeeeps的答案。 还有另一种在一个线程中处理大量连接的方法,而不会产生昂贵的进程。 Gevent与多处理/多线程有类似的api。

文档和教程:

还有一个用于抓取网址的python框架: http://scrapy.org/

来自docs asyc / sync抓取网址的示例:     import gevent.monkey     gevent.monkey.patch_socket()

import gevent
import urllib2
import simplejson as json

def fetch(pid):
    response = urllib2.urlopen('http://json-time.appspot.com/time.json')
    result = response.read()
    json_result = json.loads(result)
    datetime = json_result['datetime']

    print('Process %s: %s' % (pid, datetime))
    return json_result['datetime']

def synchronous():
    for i in range(1,10):
        fetch(i)

def asynchronous():
    threads = []
    for i in range(1,10):
        threads.append(gevent.spawn(fetch, i))
    gevent.joinall(threads)

print('Synchronous:')
synchronous()

print('Asynchronous:')
asynchronous()