V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
aragakiiyui
V2EX  ›  Python

关于迭代器的操作

  •  
  •   aragakiiyui · 2015-06-29 09:59:39 +08:00 · 3132 次点击
    这是一个创建于 3195 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我想问一下各位大神有没有什么方法更快的去遍历一个迭代器。

    我要处理的一个Iterators大概包含了将近900万个元素。如果直接用 for ... in ... 的方式去遍历,根本无法再规定的时间内完成需求。
    我目前是用iteratool.islice去做,每个线程切1000个出来,转成列表来处理,但是几乎没什么提升。而且转换成list这个操作也很耗时间....有没有什么方法可以多线程去取里面的元素?或者有没有什么其他好的方法或者经验?
    27 条回复    2015-07-01 19:02:53 +08:00
    hahastudio
        1
    hahastudio  
       2015-06-29 10:06:28 +08:00
    这个,基本上,很难
    因为一个 iterator 的当前值很有可能是会跟前几次迭代有关的,比如用 generator 写一个 Fibonacci 生成

    不知道少开几个线程会怎么样,比如一个线程处理 100W 个这样的
    实在不行,用 C/C++ 吧
    neoblackcap
        2
    neoblackcap  
       2015-06-29 10:10:39 +08:00
    为什么要去遍历一个迭代器?要不说说你具体的需求?你是不是要查找某个元素,还是说必须对每个元素都进行某种操作?
    bigtan
        3
    bigtan  
       2015-06-29 10:12:40 +08:00 via Android
    试试cython,不过还是要看你需要什么操作
    echo1937
        4
    echo1937  
       2015-06-29 10:22:34 +08:00
    用generator去实现,然后多线程去遍历?
    yuankui
        5
    yuankui  
       2015-06-29 10:28:02 +08:00
    知道有GIL这个东西吗?

    CPU密集型的job基本多线程与单线程没啥区别...

    如果机器cpu没跑满的话,可以试试[多线程](http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431927781401bb47ccf187b24c3b955157bb12c5882d000)

    再不行,就分布式吧~
    yuankui
        6
    yuankui  
       2015-06-29 10:28:38 +08:00
    笔误 [多线程]->[多进程]
    aragakiiyui
        7
    aragakiiyui  
    OP
       2015-06-29 10:31:15 +08:00
    @neoblackcap @bigtan 其实我程序的功能就是把es中某个表的所有元素取出来,然后对每个元素进行一些处理,最后放到一个新的表中。 拿的这个过程请忽略,反正就是拿出了一个包含800多万数据的迭代器。我想知道有没有什么方法,可以将这个迭代器拆成多个部分去多线程处理?如果直接跑一个for循环的话需要将近两个小时,完全没法完成需求。。。
    mhycy
        8
    mhycy  
       2015-06-29 10:31:22 +08:00
    单线程遍历并异步分发,多线程处理。。。
    aragakiiyui
        9
    aragakiiyui  
    OP
       2015-06-29 10:33:14 +08:00
    @hahastudio 我测了一下,发现使用islice拆分的话,islice操作占到总时间的40%以上。线程开多了反而更慢。
    aragakiiyui
        10
    aragakiiyui  
    OP
       2015-06-29 10:33:45 +08:00
    @mhycy 嗯,我现在打算这么试试看,能改进一些么。
    mhycy
        11
    mhycy  
       2015-06-29 10:36:16 +08:00
    @aragakiiyui
    你没说清楚你的那个处理是做啥的能改善多少没法说清。。。
    如果是CPU压力大的应用,写个C/C++扩展吧,多进程是必须的了。
    如果是IO压力大的应用,改善IO才是最重要的。

    关键是我们不知道你做的是啥操作。。。
    说回来800W数据都在内存?
    0bit
        12
    0bit  
       2015-06-29 10:37:35 +08:00
    为啥不在取的时候处理呢,分发给多进程,用offset来取数据
    seki
        13
    seki  
       2015-06-29 10:59:19 +08:00
    multiprocessing map 不知道管不管用
    aragakiiyui
        14
    aragakiiyui  
    OP
       2015-06-29 11:00:06 +08:00
    @mhycy 那我详细说一下吧,我要做的工作是把es中的3个表并作一个表。我要遍历其中三个表中主要的那个表然后结合另外两个表中对应的数据,把数据一条一条拼起来。最后将拼好的数据写到一个新的表中。写操作大概每次1000条效率最高。
    使用es的接口取出的那个表是个迭代器,所以800w数据不直接放内存里的。
    neoblackcap
        15
    neoblackcap  
       2015-06-29 11:13:48 +08:00   ❤️ 1
    @aragakiiyui 既然是从es里面拿的,为什么还有自己切分数据?根据条件筛选出来不就好了,然后就可以直接分布式。

    比如client从redis或者rabbitmq里面提取要处理的数据主键范围(eg. 1-1000 或者2000-3000)然后根据这个条件从es里面筛选出结果,然后就自行进行处理,然后写入数据库。这样你看行不?
    mhycy
        16
    mhycy  
       2015-06-29 11:18:34 +08:00   ❤️ 1
    @aragakiiyui
    8000000/1000/3600=2.222222222
    写入就两小时。。。囧
    arbipher
        17
    arbipher  
       2015-06-29 11:43:12 +08:00
    原始数据是迭代器,"转换成list"的话,不是凭空多了很多内存复制?
    mozartgho
        18
    mozartgho  
       2015-06-29 11:44:37 +08:00
    写C/C++扩展吧,一般这种效率至上的考虑用C/C++
    aragakiiyui
        19
    aragakiiyui  
    OP
       2015-06-29 12:04:33 +08:00
    @neoblackcap 我来试试看。
    aragakiiyui
        20
    aragakiiyui  
    OP
       2015-06-29 15:57:43 +08:00
    @neoblackcap 我试过了,直接条件筛选后,整体更加慢了,这样还不如直接全部取出来切分,而且我试了一个队列从迭代器中读取数据,另外开五个线程执行写的任务,虽然快了一点,但是效率提升仍然不明显。。。
    nullcc
        21
    nullcc  
       2015-06-29 16:00:48 +08:00
    考虑下map reduce?
    aragakiiyui
        22
    aragakiiyui  
    OP
       2015-06-29 16:05:00 +08:00
    @nullcc 用多进程么?!
    neoblackcap
        23
    neoblackcap  
       2015-06-29 16:12:53 +08:00
    @aragakiiyui 你这个工作差不多都已经完全是分布式了,你至少是用多进程啊。队列只是拿worker要完成那种任务的条件而已,

    就好像你告诉worker要去处理1-1000的记录,worker2处理2000-3000的记录,但是具体的信息还是要通过es去读(每个worker独自建个连接连es来获取信息)。若是你的数据没有依赖关系的话,即worker1处理完的内容可以直接写入数据库,那么你就完全连合并的server端都省了,worker直接写数据库就可以了。这样下来效率应该很高才对啊。处理完全是分布式啊,最大的瓶颈就是磁盘IO而已。即es的读或者数据的写
    clino
        24
    clino  
       2015-06-29 16:19:07 +08:00
    "我要处理的一个Iterators大概包含了将近900万个元素"
    把元素分段,然后这样可以用多个 iterator 来不重复地遍历,这样就可以多线程或者多进程地并行了
    nullcc
        25
    nullcc  
       2015-06-29 16:32:35 +08:00
    @aragakiiyui 怎么说呢。。map reduce是一种编程模型,有分布式的概念了
    julyclyde
        26
    julyclyde  
       2015-07-01 18:06:19 +08:00
    先把迭代器list化,然后再用slice的话小心内存占用量哦
    aragakiiyui
        27
    aragakiiyui  
    OP
       2015-07-01 19:02:53 +08:00
    @neoblackcap @clino 我多进程也试了,我把那块大的数据分成了2块,然后跑两个进程,发现比单进程慢的多。然后我又试了分成四块,跑四个线程,依然不如单线程跑。。我的机器实在太渣了。。瓶颈确实在IO上面。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3294 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 13:50 · PVG 21:50 · LAX 06:50 · JFK 09:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.