python wait notify_java与python多线程wait,notify操作比较

wait 和notify的应用场景

在学习wait,notify之前首先需要解释java中wait()和notify()的应用场景。wait和notify提供了对多个线程之间的等待和通知操作。例如抓取站外多张图片通常会通过多个thread同时进行,但主线程需要等到这批数据返回的结果。

多线程操作通常都有提交者(submiter)和执行者(executor),java通过concurrent包提供的Executors提供了很好的支持,如果不通过wait和notify,只能通过轮循来实现,实际上是很低效的:

看看之前我们网站的fetch实现方式:

def fetch(self, url):

for i in range(2):

title, images = build_fetch(url).fetch(url)

if images:

break

if images:

images = images[:150]

self._finished = False

self._total = len(images)

current = 0

while current < self._total:

self.pool.queueTask(self.check_image, images[current:current + self._per_check], self.collect_image)

current = current + self._per_check

from time import sleep

# 等待抓取完毕

while not self._finished:

sleep(0.05)

pass

return title, self._urls

java

首先可以这样理解,每个object实际上自身和一个monitor(锁)关联,object.wait(timeout) :使当前线程放弃object的锁并等待,除非其它线程调用了object.notify()或者object.notifyAll(),或者使等待线程中断,或者等待了timeout时间。

object.notify():随机唤醒一个等待在object的线程 ,该线程和其他活动线程一起争夺object的锁。

object.notifyAll():唤醒所有等待在object的线程 ,线程和其他活动线程一起争夺object的锁。

根据 java api doc ,使用wait,notify注意事项:

1. 调用线程必须已经获得了object的锁,即在synchronized方法或者synchronized(object){}语句块中调用。

2. 调用线程被唤醒后实际上并不会立即执行后续操作,它要先和其它活动线程竞争获得当前对象的锁,得到对象锁后才能接着执行wait后代码。

下面是一个例子:

public class Tester3 {

public synchronized void take() {

System.out.println("take");

try {

Thread.currentThread().sleep(5000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

public synchronized void put() {

System.out.println("put");

}

/**

* @param args

*/

public static void main(String[] args) {

final Tester3 tester = new Tester3();

Thread t = new Thread(new Runnable() {

@Override

public void run() {

System.out.println("take begin");

tester.take();

System.out.println("take end");

}

});

t.start();

t = new Thread(new Runnable() {

@Override

public void run() {

System.out.println("put begin");

tester.put();

System.out.println("put end");

}

});

t.start();

}

}

输出(put必须等到get释放锁之后才能被执行):

take begin

put begin

take

take end

put

put end

python

python对象没有隐式的和一个锁关联,且python中的 wait,notify是由python语言自身利用锁(Lock)实现,实现类为Condition,但是概念思想上是和java保留一致,如果要模拟 java的话,只需创建python对象时,显式将一个Condition实例赋给创建对象的一个成员属性,那么可以对应java中的doc来看一下 python的实现:

threading.py Condition类:

1。wait,notify必须在获得当前对象锁的前提下:

def wait(self, timeout=None):

if not self._is_owned():

raise RuntimeError("cannot wait on un-aquired lock")

.......

def notify(self, n=1):

if not self._is_owned():

raise RuntimeError("cannot notify on un-aquired lock")

.......

可见在wait,notify时都要进行检查,其中self._is_owned()正是判断调用线程是否获得了Condition的内置锁,也即java中对象monitor的概念。

2.wait调用后会使当前线程放弃已经获得对象锁:

def wait(self, timeout=None):

.....

saved_state = self._release_save()

其中 self._release_save正是进行了放弃Condition内置锁的操作,也对应着java先放弃对象monitor的概念

3.wait 使当前线程等待的实现

java doc说明:将当前线程加入object的waitset,然后等待。

python实现为:当前线程在一个新建锁上等待,把该锁加入到condition的等待数组中,线程等待锁的release

def wait(self, timeout=None):

...

#新建一把锁

waiter = _allocate_lock()

#现获得一次,后面再获得就阻测

waiter.acquire()

#记录等待

self.__waiters.append(waiter)

.....

if timeout is None:

#在该锁上等待

waiter.acquire()

if __debug__:

self._note("%s.wait(): got it", self)

4.notify唤醒等待线程实现

同java不同,java notify唤醒的线程不能确定,而python则能确定,一定是第一个调用wait的线程被唤醒,即为先进先出的队列结构。

对于python为:release __waiters等待数组的第一个锁,对应的等待线程即可重新开始在wait函数内运行:

def notify(self, n=1):

....

waiters = __waiters[:n]

for waiter in waiters:

#锁释放,意味着等待锁的对应线程可是从wait函数运行

waiter.release()

try:

__waiters.remove(waiter)

except ValueError:

pass

5.唤醒线程和其他活动线程争夺对象锁

唤醒线程并不是立刻从wait()返回开始它的实际操作,而是要先争夺conditon的内置锁,即java的object monitor:

def wait(self, timeout=None):

#等待在新建锁上

if timeout is None:

waiter.acquire()

#新建锁释放了,但是要先获得condition内置锁才能返回

self._acquire_restore(saved_state)

6.wait的超时处理与notifyAll 略

实例:

分别用java与python实现了经典的生产者与消费者模型

原文:http://yiminghe.iteye.com/blog/673379

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python的多线程和Java的多线程在概念上是相似的,都是指在一个程序中同时执行多个线程来实现并发性。然而,在实现上存在一些联系和区别。 联系: 1. 目标都是实现并发编程,充分利用多核处理器或提高I/O密集型任务的性能。 2. 都需要操作系统和计算机硬件的支持,通过操作系统的调度来实现线程的执行。 区别: 1. GIL(Global Interpreter Lock):Python中有全局解释器锁(GIL)的存在,它会限制同一时间只有一个线程能够执行Python字节码。这意味着在CPU密集型任务中,Python的多线程无法实现真正的并行性能提升。而Java没有类似的全局解释器锁,可以实现多个线程的并行执行。 2. 线程模型:Python的多线程是基于线程模型的,一个进程中的所有线程共享相同的内存空间。这意味着多个线程可以直接访问和修改共享数据,但也需要考虑线程安全性和同步机制。而Java的多线程是基于进程模型的,每个线程都有自己独立的内存空间,线程之间通过共享对象进行通信。 3. 多线程库:Python使用`threading`模块来实现多线程编程,提供了创建和管理线程的功能。Java则提供了`java.lang.Thread`类和其他相关类来支持多线程编程。 4. 线程同步机制:Python的多线程可以使用互斥锁(Lock)、条件变量(Condition)、信号量(Semaphore)等同步机制来保证线程安全。Java提供了类似的同步机制,如`synchronized`关键字、`wait()`和`notify()`方法等。 总而言之,Python的多线程和Java的多线程都是实现并发编程的方式,但在实现上存在一些区别。Python的多线程受到GIL的限制,无法实现真正的并行性能提升,而Java的多线程可以充分利用多核处理器并实现并行计算。此外,它们在线程模型、多线程库和线程同步机制等方面也有一些差异。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值