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

Python 的异步如何应用在普通操作上?

  •  
  •   billion ·
    kingname · 2017-07-17 17:35:19 +08:00 · 3657 次点击
    这是一个创建于 2676 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前网上能找到的关于 Python 的异步操作,几乎都是各种 HTTP 请求或者 Sockets 连接。然而却鲜有文章讲解如何用异步来进行普通的操作。

    例如我有一百个 1G 的 txt 文件,我想让 Python 异步读取他们。这个操作用 Python 3.6 的 async 与 await 如何实现呢?

    如果我有很多普通的 Python 操作,例如复制文件,删除大文件等等操作,如何使用异步而不是多线程来完成这些操作?

    如果在 Golang 里面,可以把这些操作放在一个函数中,然后go delete('xxx.txt') 他就会异步去执行了。可是在 Python 里面,似乎有点让人摸不着头脑。

    17 条回复    2017-07-18 22:43:25 +08:00
    JhZ7z587cYROBgVQ
        1
    JhZ7z587cYROBgVQ  
       2017-07-17 18:01:28 +08:00
    文件 io 的话可以看下这个 https://github.com/Tinche/aiofiles

    用协程主要是为了 io 操作不阻塞下一步的代码被执行,可以充分利用 cpu,所以很多例子都是网络 io 方面的
    janxin
        2
    janxin  
       2017-07-17 19:19:47 +08:00
    只是标准库不提供这个功能,而且本质上来说,网络 IO 在普通 Web 应用里更容易阻塞,本地 IO 一般会更快。何况,实在不行还能上 SSD 不是
    billion
        3
    billion  
    OP
       2017-07-17 19:57:47 +08:00
    @janxin 实际上因为并非所有的操作都有第三方库支持,所以我希望能找到一种通用的异步开发方法。
    lolizeppelin
        4
    lolizeppelin  
       2017-07-17 20:50:12 +08:00 via Android
    不改任何代码想实现的话直接 eventlet 就好了
    yonka
        5
    yonka  
       2017-07-17 20:58:53 +08:00
    只有阻塞 api 的操作,可以参考:


    ```python
    req_future = asyncio.get_event_loop().run_in_executor(
    self.executor,
    lambda: session.send(req)
    )
    r = await asyncio.wait_for(req_future, 15)
    ```
    billion
        6
    billion  
    OP
       2017-07-18 07:37:10 +08:00
    @lolizeppelin 这个可以实现对任何操作进行异步吗?
    billion
        7
    billion  
    OP
       2017-07-18 07:37:53 +08:00
    @yonka 这里的 self.executor 可以是任何函数吗?
    yonka
        8
    yonka  
       2017-07-18 09:26:34 +08:00
    @billion 既然是 executor 那就应该是个 executor 呀
    billion
        9
    billion  
    OP
       2017-07-18 10:42:36 +08:00
    @yonka 那这个 executor 是什么东西。写法有要求吗
    yonka
        10
    yonka  
       2017-07-18 11:02:50 +08:00
    yylucifer
        11
    yylucifer  
       2017-07-18 11:03:36 +08:00
    @billion 你这个想法我有过,经过几个月的学习和尝试,事实告诉我这可能做不到。
    lolizeppelin
        12
    lolizeppelin  
       2017-07-18 11:24:08 +08:00
    eventlet 通过 hack os 库 实现不改代码的 write read 异步
    但是你想不去深入,希望库帮你什么都异步好是做不到的
    不了了解具体原理你用都用不好

    老老实实学习异步的实现过程再找最适合的来用
    linw1995
        13
    linw1995  
       2017-07-18 17:34:11 +08:00
    ```python
    from concurrent.futures import ThreadPoolExecutor as Pool
    filenames = [...]
    def readFile(filename):
    with open(filename, encoding='utf-8') as f:
    content = f.read()
    return content # or do what you want

    with Pool(10) as executor:
    results = executor.map(readFile, filenames)
    for result in results:
    print(result)
    ```
    linw1995
        14
    linw1995  
       2017-07-18 17:34:53 +08:00
    用 ThreadPoolExecutor 就可以咯
    billion
        15
    billion  
    OP
       2017-07-18 17:52:49 +08:00
    @linw1995 你们都理解错题意了。读文件只是举个例子。我希望能实现对任何操作进行异步处理,并且能自定义回调函数。就像 JavaScript 一样。你这个代码没有实现回调函数的功能阿。
    linw1995
        16
    linw1995  
       2017-07-18 22:10:19 +08:00   ❤️ 1
    @billion
    仔细看下文档就知道了,如果要回调,就使用 ThreadPoolExecutor().submit(func, args),会返回一个 future 对象,他有 add_done_callback 方法。文档在这,https://docs.python.org/dev/library/concurrent.futures.html#concurrent.futures.Future.add_done_callback
    想看例子的,可以看下这篇文章
    http://masnun.com/2016/03/29/python-a-quick-introduction-to-the-concurrent-futures-module.html

    concurrent.futures 是个特别容易使用的异步库,哈哈。twisted 什么的太复杂了,async/await 也挺不错的,写法也还简单,不过题主问的问题是要把普通操作变成异步的……那就是把普通函数做成异步的,我是这么理解的,所以就用这个最合适了。
    lolizeppelin
        17
    lolizeppelin  
       2017-07-18 22:43:25 +08:00   ❤️ 1
    io 异步就用 epoll/select 监控 fd

    密集计算中间自己控制放弃 cpu 一般用协程,yeid 和 greenlet 之类

    封装来封装去底层最后的实现基本都这样,c 怎么写 python 也怎么写
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5771 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 03:05 · PVG 11:05 · LAX 19:05 · JFK 22:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.