不是说协程不用加锁吗?

2017-09-02 00:21:52 +08:00
 51300520
我用基于 gevent 的爬虫,如果不加锁,pymysql 的数据库操作会出错。我看很多网上教程说协程不用像线程那样加锁是优势,我还是对协程原理不是很了解, 照这样看来,写同一个文件,操作数据库,还是需要加锁的,那为什么 python 自带的 queue 在协程里面不加锁各种 get,put 也工作得很好?它是怎么做到的?
协程和线程到底有什么区别? 都是在一个进程里面切换,不加锁都会出错
9430 次点击
所在节点    Python
7 条回复
mlyy
2017-09-02 06:49:10 +08:00
coroutine 不能完全等于单线程。因为 await 本质相当于 yield,出让当前执行栈的执行权(防止阻塞)。也就是说,同一时刻内存中存在多个,不一定相互重叠的执行栈。说白了,多线程的调度是操作系统的 scheduler,而 coroutine 的调度是你的代码。
mlyy
2017-09-02 06:53:20 +08:00
至于 queue 为何"正确"(undefined behavior),不如贴出你的测试代码,看看是否真的实现了 await 操作。
NoAnyLove
2017-09-02 08:54:01 +08:00
具体事情具体讨论,并没有说协程就一定不加锁,协程本身的某些功能实现也是通过线程池实现的;就算没有用到其他线程,假如一个操作需要连续性地完成,那么也是需要借助锁的概念。asyncio 和 gevent 库中都有实现 threading 下的一些同步机制,比如 Lock、Semaphore 等,虽然和 threading 的底层的实现不同,但是同样起到了保证一些操作顺序、不会被打断地执行。

另外,queue 自带锁
misaka19000
2017-09-02 10:41:31 +08:00
> 协程是用户态相互协作的线程

你看,本质上还是线程,所以还是可能存在竞争条件,所以需要加锁
lolizeppelin
2017-09-02 13:56:00 +08:00
谁和你说不用加锁的...
oneoo
2017-09-03 10:14:06 +08:00
协程都是平等、并行的多个任务,它本身并不是多线程,每次运行的都是某个代码片段,go 是通过多线程来执行这些代码片段,才让大家误解。

但协程的代码里面有可能会调用到底层的 C 代码,如很多库就是 C 写的,如果这个库没做好多线程的锁操作,就会出现帖子说的事。这也说明这个库实现有严重问题


有兴趣可以去看看 OpenResty、Nginx+Lua,也是协程的世界。但这个世界里连“锁”的任何操作方法都没暴露给开发者,就是因为协程本身是不需要锁的。底层的事情就应该完整隐藏起来,这样使用者才不会遇到这种摸不着头脑的事
oaoouo
2017-09-04 10:42:26 +08:00
补充一下, Python 的一些数据结构是线程安全的(比如 collections 模块的 deque 结构), 使用这些结构多线程就可以不用加锁.

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

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

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

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

© 2021 V2EX