101、Python并发编程:Condition实现“排排坐分果果”的复杂同步

南宫理的日志录 2024-11-25 08:12:47
引言

前面介绍了Python并发编程中,可以使用互斥锁或者可重入锁来实现多线程之间的同步。但是,直接使用锁的同步,主要是对临界区的简单保护,确保任意时刻只有一个线程进入临界区操作临界资源。

由于多线程的调度涉及到时间片轮转、GIL等,执行的顺序是无法精确控制的。

如果想要实现更加精确的线程执行顺序的控制,类似于多线程交替执行的效果,可以考虑使用Condition。

本文的主要内容有:

1、需求场景:排排坐,分果果

2、使用锁的效果

3、使用Condition真正实现需求

4、Condition的实现原理及使用注意事项

需求场景:排排坐,分果果

假设我们有这样一个需求场景:

1、总共有10部质量参差不齐的小米15

2、张三和李四平分这10部手机

3、为了尽量公平,俩人轮流进行挑选,每人每次选一部,然后由下一个人来选,直至所有的手机瓜分完成。

接下来我们通过锁和Condition来分别尝试实现该需求场景。

使用锁的效果

直接看代码:

对代码做一个简单说明:

1、通过继承Thread类实现自定义选手机的线程,初始化方法中,传入的参数:name表示姓名,count表示每人可以选的个数,lock就是尝试同步步调的锁。

2、通过重载run()方法,实现选手机的业务逻辑,通过一个延时模拟效果。

执行结果如下:

从执行结果中,我们可以看到明显的不公平出现了。实际上,如果我们不进行延时的设置,会更加不公平,可能的结果是张三调了5个之后,李四才开始选。

显然,通过锁试图实现两个线程实现交替执行的线程同步,是无法达到预期的效果的。

使用Condition真正实现需求

接下来,通过Condition来尝试实现该需求。

直接看代码以及执行效果,之后再来解释Condition的使用

程序的执行效果:

可以看到,真正实现了“排排坐,分果果,我一个,你一个”的效果。

Condition的实现原理及使用注意事项

Condition的实现原理

从上面的文档中可以看出Condition的实现原理:

1、每个Condition对象包含一个可重入锁(RLock),也可以在创建时传递一个锁对象。用于控制对共享资源的访问。这个内部锁保证了条件变量的操作是原子的。

2、Condition对象实现了__enter__()和__exit__()这两个上下文管理的魔术方法,所以,可以使用with语法糖来使用Condition。

3、Condition对象中维护了一个等待队列,用于记录当前等待该条件的线程。当条件满足时,可以通过notify()方法或者notify_all()方法来唤醒等待的线程。

Condition对象最核心的方法有:

1、wait()方法:将调用wait()方法的线程加入到等待该条件的等待队列中。

2、notify()方法:从等待队列中唤醒一个等待的线程。

3、notify_all()方法:唤醒等待队列中的所有线程。

使用注意事项

Condition可以实现更加精准的线程同步机制,但是,在使用过程中,需要特别注意一些关键点,从而确保程序能够正确、安全地执行。

1、Condition通常用来保护共享资源,当要访问共享资源时需要获取Condition内部的锁,以避免数据竞争和资源争用。所以在访问或修改共享资源之前,务必先获取锁。

2、为了确保锁的获取和释放能够正确执行,应当尽量使用with语句来管理,这样可以方便地在代码块退出时实现锁资源的自动释放,即便有异常发生。

3、多个线程之间的复杂交互,有可能导致死锁。所以,在设计时应当尽量小心,确保所有需要获取的锁按固定顺序进行获取和释放,避免交叉请求多个锁的情况。

4、Condition.wait()方法可以接收一个timeout参数,用于表示超时自动退出等待的场景。处理超时情况时,必须清晰定义超时后的操作逻辑。

总结

本文简单介绍了Condition的内部设计原理、Condition的核心方法,以及在使用Condition实现多线程的复杂同步需求时的注意事项。

以上,就是本文的全部内容了,希望对您有所帮助!

0 阅读:12

南宫理的日志录

简介:深耕IT科技,探索技术与人文的交集