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

CURDboy 问问各位,mysql 怎么多线程 insert 数据啊...

  •  
  •   Va1n3R · 2017-12-19 17:55:43 +08:00 · 3703 次点击
    这是一个创建于 2563 天前的主题,其中的信息可能已经有所发展或是发生改变。

    python3 写了个爬虫。
    多线程爬取数据写入数据库
    一开始使用的是 sqllite3,一直提示 database is blocked,后来发现 sqllite 不支持多线程读写
    然后谷歌搜了一下,看到了别人推荐使用 mysql 来做这种任务...我只会基础的 CURD 操作,用了简单的多线程来操作,然而 mysql 貌似也不能直接多线程插入数据,stackoverflow 里面的老哥们说是需要建立连接池...头疼,之前只接触过基础的操作,请各位 V2er 赐教
    python3 代码:

    def getExin():
        while not Q.empty():
            i = Q.get()
            .*
            try:
                .*
            except :
                continue
            try:
                c.execute("INSERT INTO exin (username, password) \
                      VALUES (%s,'%s')" % (username, password))
                conn.commit()
            except:
                pass
    
    
    for i in range(0, 99475):
        if len(str(i)) < 5:
            i = (5 - len(str(i))) * "0" + str(i)
        Q.put(i)
    
    threads = []
    
    conn = connect(user='root', password='root', database='test')
    c = conn.cursor()
    for i in range(800):
        x = threading.Thread(target=getExin,args=())
        threads.append(x)
    for t in threads:
        t.start()
    c.close()
    print("All done")
    
    24 条回复    2017-12-20 16:20:48 +08:00
    misaka19000
        1
    misaka19000  
       2017-12-19 18:01:57 +08:00
    一个线程对应一个链接就行了
    Va1n3R
        3
    Va1n3R  
    OP
       2017-12-19 18:23:43 +08:00 via iPhone
    @misaka19000 尝试过会提示连接不上,我这里是 1000 线程
    zeraba
        4
    zeraba  
       2017-12-19 18:27:29 +08:00 via Android
    executemany 不行么 是什么场景非要多线程多个事务去写入哪
    Va1n3R
        5
    Va1n3R  
    OP
       2017-12-19 18:30:07 +08:00
    @zeraba 访问一次目标获取一次信息,然后写入数据库,就这么简单的逻辑,但是单线程太慢了...
    zeraba
        6
    zeraba  
       2017-12-19 18:36:42 +08:00 via Android
    @Va1n3R 要么一次一次写 redis 要么把取回的数据先存成 list 或者 tuple 到了一定的量再批量插入 mysql 你这么搞 太费资源了
    Va1n3R
        7
    Va1n3R  
    OP
       2017-12-19 18:47:00 +08:00
    @zeraba 资源不是问题,只是不想把简单问题复杂化,谢谢老哥啦
    Cooky
        8
    Cooky  
       2017-12-19 19:00:05 +08:00 via Android
    你这只是一个连接多线程使用吧
    kiwi95
        9
    kiwi95  
       2017-12-19 19:02:08 +08:00
    你现在 Q 是共享的,那 Q 的 get,put 是不是阻塞的?然后多个线程也是操作一个连接作数据插入,这样多线程有什么意义呢,除非你的数据准备阶段占时间开销的大头,否则这样并不能提升速度
    likuku
        10
    likuku  
       2017-12-19 19:10:46 +08:00
    老生常谈提示下:得用 InnoDB
    Va1n3R
        11
    Va1n3R  
    OP
       2017-12-19 19:49:43 +08:00
    @Cooky 我尝试过多线程每个都链接一次,但是 mysql 会拒绝我的访问....我开了 800~1000 的线程
    Va1n3R
        12
    Va1n3R  
    OP
       2017-12-19 19:50:48 +08:00
    @kiwi95 Q 是 queue,应该不会阻塞吧,速度提升确实肉眼可见啊...
    Sanko
        13
    Sanko  
       2017-12-19 20:27:23 +08:00 via Android
    executemany 应该不慢吧
    Va1n3R
        14
    Va1n3R  
    OP
       2017-12-19 22:39:17 +08:00
    @Sanko
    @zeraba 数据量挺大的,直接放入字典,我怕内存会爆啊
    Cooky
        15
    Cooky  
       2017-12-19 23:57:09 +08:00 via Android
    @Va1n3R 看看 MySQL 默认最大连接数多少,改下配置
    HanSonJ
        16
    HanSonJ  
       2017-12-20 00:02:21 +08:00
    这种情况,批量 insert 最佳

    插入速度优化上百倍
    billlee
        17
    billlee  
       2017-12-20 00:16:19 +08:00
    你如果不批量插入,开再多线程,HDD 上一秒也只能提交 100 个事务。
    jimzhong
        18
    jimzhong  
       2017-12-20 04:29:27 +08:00
    你开多线程获得的性能提升未必有批量插入大。
    huhujin
        19
    huhujin  
       2017-12-20 09:22:40 +08:00
    我瞎比说说:
    for i in range(800):
    x = threading.Thread(target=getExin,args=())
    t.setDaemon(True)
    x.start()
    2ME
        20
    2ME  
       2017-12-20 09:26:17 +08:00
    不懂 py .. 不过你这么搞肯定有问题 线程开太高 mysql 最大连接数会有问题 就算连得上 你 IO 还是会有问题 和#18 说的一样 你开多线程不一定有拼接 sql 批量插入来的实在
    catinred
        21
    catinred  
       2017-12-20 10:16:05 +08:00
    中间用个队列把数据存起来 然后起个线程批量插入就好了
    exiaohao
        22
    exiaohao  
       2017-12-20 10:57:48 +08:00
    这种事吧,celery 就好啦 gevent 开起来妈妈再也不用担心并发上不去了
    搞 thread 多麻烦
    Va1n3R
        23
    Va1n3R  
    OP
       2017-12-20 16:20:08 +08:00
    @2ME 已经采用了 executemany 啦
    Va1n3R
        24
    Va1n3R  
    OP
       2017-12-20 16:20:48 +08:00
    @exiaohao 之前没有写过协程、异步。昨晚看了一下,启发很大
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1030 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:57 · PVG 03:57 · LAX 11:57 · JFK 14:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.