在下小白,在网上找了很多异步 I/O 教程,都是关于 python3 的 asyncio。python2 只有 yield、send 吗
1
shawlib 2017-08-19 10:52:37 +08:00
什么系统?
|
2
BBCCBB 2017-08-19 10:56:13 +08:00
python2 就用 gevent 咯
|
3
Zioyi OP windows? 难道说 linux 的 python2 支持?
|
4
shawlib 2017-08-19 10:59:26 +08:00
windows 不支持 signal(),我也是刚刚遇到这个问题,还不知道怎么解决
|
5
SearchDream 2017-08-19 11:34:38 +08:00 via iPhone
试试 Tornado
|
6
NoAnyLove 2017-08-19 12:19:34 +08:00 1
即使是 Python 3 asyncio 在 Windows 上也是不支持异步文件操作的,我也很绝望啊,明明 ProactorEventLoop 用的 IOCP 是支持文件读写的,完全不知道为啥独裁者大人不开发对应的文件支持功能,搜索了半天也没搜索到结果和原因,全程懵逼状态。。。。。。
还是得看你具体什么 I/O 操作,是在什么操作系统上,至少 Windows 上的文件和 socket 是不同的。而且,如果是用 select 也可以被称作异步 I/O,只不过没有用到协程罢了。你的问题有点太宽泛了,不够具体。 另外,如果你会搜索的话,就会知道,还有个东西叫做 Trollius |
7
lcdtyph 2017-08-19 13:10:48 +08:00 via iPhone
纯异步的话可以试试 pyuv,是基于 libuv 封装的,在 win 上底层是 iocp
|
8
aheadlead 2017-08-19 16:00:42 +08:00
不试试 executemany 吗?
|
9
JhZ7z587cYROBgVQ 2017-08-19 16:07:42 +08:00
附议 executemany 啊
|
10
wucao219101 2017-08-19 16:09:45 +08:00
Twisted
|
11
realpg 2017-08-19 16:25:07 +08:00
啥数据库?
|
12
ghostheaven 2017-08-19 16:31:01 +08:00 via Android
你确定性能瓶颈在 python 吗
|
13
director 2017-08-19 23:20:20 +08:00
mark
|
14
NoAnyLove 2017-08-20 00:04:56 +08:00 1
那么问题来了,具体是什么数据库?经过什么中间架构进行连接的吗(比如是不是要经过 HTTP 请求对数据库进行操作)?还是直接对数据库进行操作?用的什么 Python 库对数据进行操作?
如果要高效地对数据库进行异步操作,那么操作数据库的 Python 库也必须是异步的,比如 aiomysql。asyncio 至少需要 3.3 才能支持,如果你坚持使用 Python 2 的话,可以选择 gevent,并且搭配支持 gevent 的异步数据库操作库,比如 ultramysql 话说,既然你的并发依赖的是数据本身提供的锁机制,为什么会觉得瓶颈是因为 Python 线程的竞争?你在 Python 上还做了什么同步机制? |
15
Zioyi OP 抱歉没有说明清楚,我使用的是 mysql 数据库,使用的 python 库是 pymysq。我使这里设置锁的原因是:我每一个线程都有一个连接数据库的链接(或者说是保持连接的句柄),如果我不加锁地去跑 50 个线程,会出现(Lock wait timeout exceeded; try restarting transaction)的报错,所以我在这里设置锁去保证同时只有一个线程去对数据库操作:
``` if self.mysql_lock.acquire(): cursor.execute(current_insert_sql) connection.commit() self.mysql_lock.release() ``` 不知我这种设计是否合理? |
16
NoAnyLove 2017-08-20 11:53:05 +08:00 1
@Zioyi 没遇到过这种情况,不过感觉(Lock wait timeout exceeded; try restarting transaction)是因为你的并发太高了?不过如果使用了 Lock,同时只有一个线程对数据库读写的话,那么感觉有点跑不够。几个选择:
1. 把 lock 换成 threading.BoundedSemaphore,然后设置一个合适的并发值(多试几次,找出一个合理的值,记得对报错的情况要 try-except ) 2. 直接引入 gevent, monkey.patch_all(),并发 50 个协程,如果出现同样的错误提示,那么很可能是并发高了,同样可以引入 gevent.lock.BoundedSemaphore 来控制并发数,或者减少协程数目。 如果出现了 2 这种情况,使用协程和多线程的性能差距应该不会特别大。异步 I/O 的性能高需要有足够高的并发数,如果瓶颈是在并发数上,你还可以试试更换其他操作 MySQL 的 Python 库,比如我前面提到的 ultramysql,主页上写的这个库支持个 gevent,star 数也不低,但是居然找不到官方文档,Orz |
18
NoAnyLove 2017-08-20 12:05:16 +08:00 1
@Zioyi Orz,突然反应过来,如果你的线程中不存在其他 I/O 操作,或者其他阻塞操作的话,按照之前的写法,你把 50 线程改成单线程,说不定会更快一些。。。。。。。 因为基本上对数据库的所有操作都放入临界区了。不过你之前既然说过 50 线程跑 14 分钟,单线程跑 40 分钟,那我只能推断你的线程中还存在了其他阻塞操作
|
19
Zioyi OP 没错,我的线程中还存在从文件中读取记录的 I/O 操作,基本代码如下:
``` with open('recors.txt', 'rb') as rf: |
20
Zioyi OP @NoAnyLove 感谢。没错,我的线程中还存在从文件中读取记录的 I/O 操作,基本代码如下:
``` ... with open(records1.txt', 'rb') as rf: record = rf.readline() while record: records.append(record) if len(records) == 500: currenct_insert_sql = function1(records) # records 列表存五百条 record 后做一次数据库 I/O if self.mysql_lock.acquire(): cursor.execute(current_insert_sql) connection.commit() self.mysql_lock.release() records = [] record = rf.readline() ... ``` 现在准备参考你的建议,尝试协程和更换 mysql 库,等测试出结果后会反馈出来。 |
21
whx20202 2017-08-23 15:17:49 +08:00
我个人感觉那些 gevent 库,都是用 I/O 多路复用(系统层面)的原理,让开发通过同步方式进行异步(代码层面)的编程
python 如果想要真正异步 IO 好像有个 pyaio,当然你的需求协程就能做 如果有错误欢迎讨论 |