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

为什么用 Python motor 会慢这么多,我做错了什么吗?

  •  
  •   naldo0193 · 2020-09-01 11:08:00 +08:00 · 2232 次点击
    这是一个创建于 1326 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近学习 aiohttp 。

    想试试 python motor 单条插入的总体时间。没想到需要 160 多秒。 如果用 pymongo 单条插入,不用 aiohttp 和 motor,总体时间只需要 23 秒。如果用 insert_many,总体时间只需要 1.4 秒

    请问各位大佬,是我 aiohttp 或者 motor 做错了什么?

    import asyncio,hashlib,time
    from aiohttp import web
    import motor.motor_asyncio
    motor_mongo_client = motor.motor_asyncio.AsyncIOMotorClient('127.0.0.1', 17177)
    
    async def mongodb_test(request):
        start_time = time.time()
        for i in range(100000):
            md5 = str(i) + u'a9cfb75778b38676'
            md5 = md5.encode('utf-8')
            md5 = hashlib.md5(md5).hexdigest()
    
            items = {
                'md5': md5,
                'i': i
            }
            try:
                await motor_mongo_client['mongodb_test']['insert_test'].insert_one(items)
            except Exception as e:
                print(e)
                continue
                
        end_time = time.time()
        const_time = end_time - start_time
        print(const_time)
        return web.Response(text="done")
    
    loop = asyncio.get_event_loop()
    app = web.Application(loop=loop)
    app.add_routes([
        web.get('/index', index),
        web.get('/mongodb_test',mongodb_test),
        ])
    
    web.run_app(app, host='127.0.0.1', port=8080)
    
    5 条回复    2020-09-01 18:59:12 +08:00
    sivacohan
        1
    sivacohan  
       2020-09-01 11:21:56 +08:00   ❤️ 1
    切换上下文是有成本的。
    await motor_mongo_client['mongodb_test']['insert_test'].insert_one(items)
    这一句会导致每一次执行到这,都会切换一下上下文。所以导致会慢。


    异步操作一般解决的是 IO 慢,导致整体并发不足的情况。在你的例子里,数据库 IO 并不是瓶颈,这个例子里,你应该使用多线程、或多进程。
    linw1995
        2
    linw1995  
       2020-09-01 13:23:28 +08:00   ❤️ 1
    motor 实际就是 pymongo + 多线程,每次操作都要另外个线程去做,完成再回调到主线程。而直接用 pymongo 就是单个线程在跑,少了上下文切换,当然快啦。并发高速度慢,并发低速度快,根据业务情况取舍吧
    bnm965321
        3
    bnm965321  
       2020-09-01 13:27:05 +08:00   ❤️ 1
    可以直接 ensure_future 还是什么函数,把协程插入到事件循环就行不要让下一个协程等待上一个执行完毕
    676529483
        4
    676529483  
       2020-09-01 15:58:18 +08:00   ❤️ 1
    你 for 循环里面用 await 就变成单线程了,试试 create_task
    Wincer
        5
    Wincer  
       2020-09-01 18:59:12 +08:00   ❤️ 1
    operations = []
    for 循环内部 await 改成:
    operations.append(motor_mongo_client['mongodb_test']['insert_test'].insert_one(items))
    然后 asyncio.gather(*operations),这才是正确的使用方法
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5308 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 06:51 · PVG 14:51 · LAX 23:51 · JFK 02:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.