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

2017-07-17 17:35:19 +08:00
 billion

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

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

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

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

3583 次点击
所在节点    Python
17 条回复
jason0916
2017-07-17 18:01:28 +08:00
文件 io 的话可以看下这个 https://github.com/Tinche/aiofiles

用协程主要是为了 io 操作不阻塞下一步的代码被执行,可以充分利用 cpu,所以很多例子都是网络 io 方面的
janxin
2017-07-17 19:19:47 +08:00
只是标准库不提供这个功能,而且本质上来说,网络 IO 在普通 Web 应用里更容易阻塞,本地 IO 一般会更快。何况,实在不行还能上 SSD 不是
billion
2017-07-17 19:57:47 +08:00
@janxin 实际上因为并非所有的操作都有第三方库支持,所以我希望能找到一种通用的异步开发方法。
lolizeppelin
2017-07-17 20:50:12 +08:00
不改任何代码想实现的话直接 eventlet 就好了
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
2017-07-18 07:37:10 +08:00
@lolizeppelin 这个可以实现对任何操作进行异步吗?
billion
2017-07-18 07:37:53 +08:00
@yonka 这里的 self.executor 可以是任何函数吗?
yonka
2017-07-18 09:26:34 +08:00
@billion 既然是 executor 那就应该是个 executor 呀
billion
2017-07-18 10:42:36 +08:00
@yonka 那这个 executor 是什么东西。写法有要求吗
yonka
2017-07-18 11:02:50 +08:00
yylucifer
2017-07-18 11:03:36 +08:00
@billion 你这个想法我有过,经过几个月的学习和尝试,事实告诉我这可能做不到。
lolizeppelin
2017-07-18 11:24:08 +08:00
eventlet 通过 hack os 库 实现不改代码的 write read 异步
但是你想不去深入,希望库帮你什么都异步好是做不到的
不了了解具体原理你用都用不好

老老实实学习异步的实现过程再找最适合的来用
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
2017-07-18 17:34:53 +08:00
用 ThreadPoolExecutor 就可以咯
billion
2017-07-18 17:52:49 +08:00
@linw1995 你们都理解错题意了。读文件只是举个例子。我希望能实现对任何操作进行异步处理,并且能自定义回调函数。就像 JavaScript 一样。你这个代码没有实现回调函数的功能阿。
linw1995
2017-07-18 22:10:19 +08:00
@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
2017-07-18 22:43:25 +08:00
io 异步就用 epoll/select 监控 fd

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

封装来封装去底层最后的实现基本都这样,c 怎么写 python 也怎么写

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/375953

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX