1 简介
我们通过可重入锁在python的同步线程中实现了 对线程异步的操作, 一个可重入锁必须由获得它的线程来释放。 一旦一个线程获得了一个可重入锁,同一个线程可以再次获得它而不阻塞。
而该线程每获得一次锁,就必须释放一次锁。 获取的锁都必须释放一次。 它获取一个信号,将内部计数器递减1。
当调用没有参数时:如果内部计数器在进入时大于 0,则将其递减1并立即返回。
如果它是零则阻塞,等待其他线程调用release(),使其大于零。
这是以适当的互锁方式进行的,因此 如果多个acquisition()调用被阻塞,release()将正好唤醒其中一个唤醒它们中的一个。
实现可能会随机选择一个,所以被阻塞的线程被唤醒的顺序为 唤醒被阻塞线程的顺序不应该被依赖。
在这种情况下,没有在这种情况下没有返回值。
当调用阻塞设置为 "true "时,做与调用 "无参数 "时相同的事情。 不带参数的情况下做同样的事情,并返回true。
当调用时将阻塞设置为false时,不要阻塞。如果一个没有参数的调用会阻塞,立即返回false;
否则,做与无参数调用时相同的事情,并返回true。
当调用时的超时时间不是None,它将阻塞最多 超时秒。
如果在这个时间段内,获取没有成功完成时间间隔内没有成功完成,则返回false。 否则返回true。
可重入锁允许线程递归获取锁,每次获取后需相应释放。在Python中,acquire()
和release()
管理内部计数器,确保正确同步。线程安全的队列在生产者(同步存入)和消费者(异步取出)间协调数据传输,展示出不同线程行为导致的输出无序性。Go中,goroutines作为轻量级协程,通过channel进行同步通信。
2 同步存入和异步取出
使用 入口判断 代码执行 同步还是异步,producer 同步 存入
def producer(q, n):
for i in range(n):
q.put(i)
q.put(None)
q = Queuey(2)
启用线程同步存入
Thread(target=producer, args=(q, 10)).start()
time.sleep(1)
启用线程循环,异步取出
loop.run_until_complete(aconsumer(q))
运行时的输出,可以看到由于同步线程和异步线程的不同操作 输出的无序的:
put sync item: 0
put sync item: 1
put sync item: 2
get async item
Async Got: 0
get async item
put sync item: 3
Async Got:put sync item: 14
get async item
Async Got:
put sync item: 2
get async item
5
Async Got: put sync item: 3
6
get async item
Async Got: put sync item: 4
7
get async item
Async Got: put sync item: 5
8
get async item
Async Got: put sync item: 6
9
get async item
Async Got:put sync item: 7None
get async item
Async Got: 8
get async item
Async Got: 9
3 同步存,异步取:go的简单例子
同步存入时需要注意,把channel的长度与调用者匹配
func SyncPutin(n int) {
AsyncQueue = make(chan int, n)
for i := 0; i < n; i++ {
AsyncQueue <- i
}
}
在消费时取出即可
func Customer(n int) {
wg.Add(1)
go func() {
var count int
for {
fmt.Println("get async item")
if count >= n {
wg.Done()
os.Exit(1)
}
count += 1
newOne := <-AsyncQueue
fmt.Println("Async Got:", newOne)
}
}()
wg.Wait()
}
运行输出
get async item
Async Got: 0
get async item
Async Got: 1
get async item
Async Got: 2
get async item
Async Got: 3
get async item
Async Got: 4
get async item
Async Got: 5
get async item
Async Got: 6
get async item
Async Got: 7
get async item
Async Got: 8
get async item
Async Got: 9
4 异步存入 和 异步取出
使用异步库的队列,存取先后顺序并不重要。 异步取 异步存
from asyncio import Queue
q = Queue()
loop.create_task(aconsumer(q))
loop.run_until_complete(aproducer(q, 10))
实际的输出
python async_third.py
Async Got: 0
Async Got: 1
Async Got: 2
Async Got: 3
Async Got: 4
Async Got: 5
Async Got: 6
Async Got: 7
Async Got: 8
Async Got: 9
5 异步存取 go的简单例子
go 的异步存入使用 内置的匿名函数即可
func PutsIn(n int) {
go func() {
for i := 0; i < n; i++ {
AsyncQueue <- i
}
}()
}
消费者保持不变
func Customer(n int) {
wg.Add(1)
go func() {
var count int
for {
fmt.Println("get async item")
if count >= n {
wg.Done()
os.Exit(1)
}
count += 1
newOne := <-AsyncQueue
fmt.Println("Async Got:", newOne)
}
}()
wg.Wait()
}
运行查看输出
go run main.go
get async item
Async Got: 0
get async item
Async Got: 1
get async item
Async Got: 2
get async item
Async Got: 3
get async item
Async Got: 4
get async item
Async Got: 5
get async item
Async Got: 6
get async item
Async Got: 7
get async item
Async Got: 8
get async item
Async Got: 9
6 小结
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方在切回来的时候,恢复先前保存的寄存器上下文和栈。
因此,协程能保留上一次调用时的状态 也就是说:
进入上一次离开时所处逻辑流的位置。
线程和进程的操作是由程序触发系统接口,最后执行者是系统
协程的操作执行子则是用户自身程序,goroutine也是协程
goroutine 是Golang语言中最经典的设计,也是其魅力所在,goroutine本质是协程 是实现并行计算的核心。
goroutine 使用方式非常简单,只需要使用go关键字即可启动一个协程并且它是处于异步方式运行的,你不需要等它运行完成以后再执行以后的代码。
通过go 关键字启动一个协程来运行函数。
go func() {}()
groutine能拥有强大的并发实现是通过GPM调度模型实现。
使用go的特性与python的经典一般用法进行比较似乎不太公平,这里只做简单对比,了解其优点.
完整代码:
https://github.com/hahamx/examples/blob/main/alg_practice/1_pys_async/asyncio_cmp.py