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
a476286557
V2EX  ›  Python

关于 for 循环与线程~~

  •  
  •   a476286557 · 2018-12-12 15:02:59 +08:00 · 2552 次点击
    这是一个创建于 2158 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我现在是

    def handle_mysql(id):
        # 修改数据库的数据
        pass
    
    id_list = [...] # 里面有一百个 id
    for i in id_list:
        handle_mysql ( i )
    

    但是这样速度比较慢,然后我想用下面的方法,但是不知道是否可行

    def handle_mysql(id):
        # 修改数据库的数据
        pass
    
    id_list = [...] # 里面有一百个 id
    for i in id_list:
        线程 1,调用 handle_mysql ( i )
        线程 2,调用 handle_mysql ( i )
        线程 3,调用 handle_mysql ( i )
    
    

    请问这样可以吗?或者您有什么更好的建议能否告诉我?

    14 条回复    2018-12-13 12:43:58 +08:00
    yosemite
        1
    yosemite  
       2018-12-12 15:12:32 +08:00
    一条任务一个线程啊!有必要吗
    a476286557
        2
    a476286557  
    OP
       2018-12-12 15:18:05 +08:00
    就弄两三个线程就行
    @yosemite
    Vegetable
        3
    Vegetable  
       2018-12-12 15:18:17 +08:00
    multiprocessing.dummy.Pool.map
    最好是使用 aiomysql 吧
    Wisho
        4
    Wisho  
       2018-12-12 15:45:20 +08:00
    把所有 id 塞到一个并发安全的队列里,然后起 N 个线程不断地从队列里取 id,执行逻辑,直到队列为空。
    Linxing
        5
    Linxing  
       2018-12-12 15:48:48 +08:00
    mq?
    likuku
        6
    likuku  
       2018-12-12 15:54:17 +08:00 via iPhone
    mysql 表 确认得是 innodb 的,否则锁表就慢慢等(的确当前还是有人默认用 myisam 表的)

    来个线程 /进程池 吧,自己再确保同时跑的任务不要超过 CPU 核数 /超线程数
    xpresslink
        7
    xpresslink  
       2018-12-12 16:50:31 +08:00   ❤️ 1
    有一个重要的事情说三遍:
    mysql 不是线程安全的,mysql 不是线程安全的,mysql 不是线程安全的

    你如果使用多线程那么需要给每个线程创建单独的 mysql 连接。
    你同时创建过多的线程和连接最大的可能性是直接把数据库给挂死了。

    最科学的办法是按照你的 mysql 的性能创建一个连接池,可以使用 DBUtils 这个包。
    你这边多线程从连接池申请连接。
    lihongjie0209
        8
    lihongjie0209  
       2018-12-12 17:03:25 +08:00   ❤️ 1
    然后你就会发现你的性能瓶颈在 mysql 上了
    largecat
        9
    largecat  
       2018-12-12 17:12:05 +08:00 via Android
    用协程吧,
    chanchan
        10
    chanchan  
       2018-12-12 17:18:24 +08:00   ❤️ 1
    我一般优先合并 sql,比如多条 insert into 变成一条 insert into (),(),()...
    wwqgtxx
        11
    wwqgtxx  
       2018-12-13 10:04:38 +08:00   ❤️ 1
    这种事情找一个成熟 orm,人家一定有最好的优化方式在大量插入
    CRVV
        12
    CRVV  
       2018-12-13 10:29:40 +08:00
    这样可行,应该会比之前快。前提是线程不共用 MySQL 的 connection,并且你的 MySQL 支持这么多的连接数

    更好的方法有
    1. 写一句 SQL 把这 100 个操作做了,大概率会快很多
    2. 不要每一句都开一个新线程,而是用一个线程池。你可以用 4 楼给的方法自己写线程池,也可以用 ThreadPoolExecutor
    3. 用 aiomysql 来并发操作数据库,这样不需要开线程,但是需要大改之前的代码

    顺便一说,“ mysql 不是线程安全的” 这句话 表义不明而且不对
    正确来说应该是,MySQL 的 driver 给你返回的 connection 不是线程安全的(也可以是线程安全的,但线程安全的 connection 没有道理,应该不会有人去写那样的代码)
    但这又是一句废话,程序里的变量几乎都不是线程安全的
    vincenttone
        13
    vincenttone  
       2018-12-13 11:14:37 +08:00
    个人猜测可能提升并不大,因为目测 python 应该是用户级线程,但是操作了网络 IO,整个进程陷入内核,导致其他线程阻塞
    But,我没用过 python 进程,所以对此了解的不够全面,只凭猜测。
    建议楼主自己写出来测试一下时间(当然也期望回复一下实验结果);第二个建议是可以考虑使用 epoll 或者 select 处理这个试试;第三个建议是如果是系统线程,最好使用连接池来管理,不然容易死
    Leigg
        14
    Leigg  
       2018-12-13 12:43:58 +08:00 via iPhone
    线程可以用于这种 io 型任务,但不要在线程任务多开 conn
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2576 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 15:08 · PVG 23:08 · LAX 07:08 · JFK 10:08
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.