【问题标题】:python multi threading/ multiprocess codepython多线程/多进程代码
【发布时间】:2010-09-08 16:18:32
【问题描述】:

在下面的代码中,我正在考虑使用多线程或多进程从 url 获取。我认为池是理想的,任何人都可以帮助提出解决方案..

想法:池线程/进程,收集数据...我的偏好是进程而不是线程,但不确定。

import urllib

URL = "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1t1v&e=.csv"
symbols = ('GGP', 'JPM', 'AIG', 'AMZN','GGP', 'JPM', 'AIG', 'AMZN')
#symbols = ('GGP')

def fetch_quote(symbols):
    url = URL % '+'.join(symbols)
    fp = urllib.urlopen(url)
    try:
        data = fp.read()
    finally:
        fp.close()
    return data

def main():
    data_fp = fetch_quote(symbols)
#    print data_fp
if __name__ =='__main__':
    main()

【问题讨论】:

  • 您还想同时做些什么吗?您的代码只执行一个请求。
  • 不,现在,我正在学习 python,所以尽量让一切变得简单。谢谢
  • 工艺方法我看过了,谁能给我看线程方法。请,谢谢。

标签: python multithreading multiprocess


【解决方案1】:

您有一个请求同时请求多个信息的进程。让我们尝试一一获取这些信息。您的代码将是:

def fetch_quote(symbols):
    url = URL % '+'.join(symbols)
    fp = urllib.urlopen(url)
    try:
        data = fp.read()
    finally:
        fp.close()
    return data

def main():
    for symbol in symbols:
        data_fp = fetch_quote((symbol,))
        print data_fp

if __name__ == "__main__":
    main()

所以 main() 调用,每个 url 一个一个地获取数据。 让我们用一个池对它进行多处理:

import urllib
from multiprocessing import Pool

URL = "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1t1v&e=.csv"
symbols = ('GGP', 'JPM', 'AIG', 'AMZN','GGP', 'JPM', 'AIG', 'AMZN')

def fetch_quote(symbols):
    url = URL % '+'.join(symbols)
    fp = urllib.urlopen(url)
    try:
        data = fp.read()
    finally:
        fp.close()
    return data

def main():
    for symbol in symbols:
        data_fp = fetch_quote((symbol,))
        print data_fp

if __name__ =='__main__':
    pool = Pool(processes=5)
    for symbol in symbols:
        result = pool.apply_async(fetch_quote, [(symbol,)])
        print result.get(timeout=1)

在下面的 main 中创建了一个新进程来请求每个符号 url。

注意:在 python 上,由于存在 GIL,因此必须将多线程视为错误的解决方案。

有关文档,请参阅:Multiprocessing in python

【讨论】:

  • GIL 在这里不是问题,因为这个任务绝对是 IO-bound。
  • 这种方法比没有多处理要慢得多。如果使用 150 只股票的列表,则错误且速度非常慢。复制上面的列表,这样库存等于 150。非常慢,线程会更好吗?????
  • @user428862 一个原因是当你的符号列表变得很慢。大小为 'coz pool.apply_async 序列化您的列表并通过管道将其传递给您的子进程。作为传递参数(到子进程)公司的大小,您将有开销。在 Windows 中,我们无能为力,但在 UNIX 中尝试这种方法。在 UNIX 中,fork(2) 用于生成进程,这些进程基本上将整个父进程状态传递给子进程。因此,如果父进程中有一些全局变量,子进程将能够访问它。因为symbols 已经是全局的,所以不要在 args 中传递它。因此没有序列化...
  • @movie,谢谢,单线程是 2 秒,多进程是 18 秒。为了比较我将如何多线程这个......或者会出现同样的问题。
【解决方案2】:

所以这里有一个非常简单的例子。它遍历符号,一次传递一个到 fetch_quote。

import urllib
import multiprocessing

URL = "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1t1v&e=.csv"
symbols = ('GGP', 'JPM', 'AIG', 'AMZN','GGP', 'JPM', 'AIG', 'AMZN')
#symbols = ('GGP')

def fetch_quote(symbol):
    url = URL % '+'.join(symbol)
    fp = urllib.urlopen(url)
    try:
        data = fp.read()
    finally:
        fp.close()
    return data


def main():

    PROCESSES = 4
    print 'Creating pool with %d processes\n' % PROCESSES
    pool = multiprocessing.Pool(PROCESSES)
    print 'pool = %s' % pool
    print

    results = [pool.apply_async(fetch_quote, sym) for sym in symbols]

    print 'Ordered results using pool.apply_async():'
    for r in results:
        print '\t', r.get()

    pool.close()
    pool.join()

if __name__ =='__main__':
    main()

【讨论】:

  • 如果检索到的页面很大,可能会出现一些问题。 multiprocessing 使用进程间通信机制在进程之间交换信息。
  • 没错,以上内容仅用于简单说明。 YMMV,但我想展示使用他的代码并使其成为多进程是多么简单。
  • 我收到了这个错误:Creating pool with 4 processes pool = Ordered results using pool.apply_async(): Traceback (last last last call): File "C :\py\Raw\Yh_Mp.py",第 36 行,在 main() 文件 "C:\py\Raw\Yh_Mp.py",第 30 行,在主打印中 '\t',r.get( ) 文件“C:\Python26\lib\multiprocessing\pool.py”,第 422 行,在 get raise self._value TypeError: fetch_quote() 中只取 1 个参数(给定 3 个)
【解决方案3】:

实际上,两者都可以做到。您可以使用异步调用在一个线程中完成它,例如来自 Twisted Webtwisted.web.client.getPage

【讨论】:

  • @vartec 无需购买任何第 3 方额外包。 Python2.6+ 及以后有很好的内置包用于这种目的。
  • 呃哦,有人提到了 Twisted,这意味着所有其他答案都会被否决。 *.com/questions/3490173/…
  • @movieyoda:嗯,出于显而易见的原因(GAE,Jython),我喜欢与 2.5 保持兼容。无论如何,也许我错过了什么,Python 2.6 引入了对异步 Web 调用的哪些支持?
  • @Nick:不幸的是,由于 GIL,Python 在线程方面很烂(我知道,函数调用是在 GIL 发布的情况下完成的),所以使用线程而不是延迟异步调用你什么也得不到。另一方面,事件驱动的编程规则即使在您实际上可以使用线程的情况下(视频:ngnix、lighttpd),显然在 Python 的情况下(Twisted、Tornado)也是如此。
  • @vartec 如果我没记错的话multiprocessing 模块从 2.6 开始在 Python 中原生可用。我认为在此之前它被称为pyprocessing,一个单独的第 3 方模块。
【解决方案4】:

如您所知,由于 GIL,Python 中的多线程实际上并不是多线程。本质上,它是在给定时间运行的单个线程。因此,在您的程序中,如果您希望在任何给定时间获取多个 url,多线程可能不是要走的路。还是在爬网之后将数据存储在单个文件或某个持久数据库中?此处的决定可能会影响您的表现。

多进程这样效率更高,但会产生额外进程的时间和内存开销。我最近在 Python 中探索了这两个选项。这是网址(带代码)-

python -> multiprocessing module

【讨论】:

  • IO 代码在不获取 GIL 的情况下运行。对于 IO 绑定的地图,threading 效果很好。
  • 我想说的是,在考虑 Python 中的多线程时,需要牢记 GIL。获取 URL 数据后,可能需要对其进行解析(创建 DOM->CPU 密集型)或直接将其转储到文件中(IO 操作)。在后者中,GIL 的效果会被低估,但在前者中,GIL 在程序的效率中发挥了重要作用。不知道为什么人们会如此冒犯他们不得不对帖子投反对票......
  • @user428862 Python 中的线程和多处理本质上具有相同的接口/API 调用。您可以只使用我的示例并导入线程而不是导入多处理。试一试,如果您遇到一些问题,我会帮助您...
  • 我是 python 新手。我查看了您的代码,没有导入。感谢您提供帮助。
  • 哦,在这种情况下应该是导入多处理。