爬虫(五):生产者消费者方法

1.不使用锁的话,可能会产生线程的竞争:当共享一个对象(变量或者一个方法)加锁的操作

在threading模块中,定义两种类型的琐:threading.Lock和threading.RLock。它们之间有一点细微的区别,通过比较下面两段代码来说明:
import threading  
lock = threading.Lock() #Lock对象  
lock.acquire()  
lock.acquire()  #产生了死琐。  
lock.release()

lock.release()

import threading  
rLock = threading.RLock()  #RLock对象  
rLock.acquire()  
rLock.acquire() #在同一线程内,程序不会堵塞。  
rLock.release()  
rLock.release()

  这两种琐的主要区别是:RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。注意:如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。threading.Condition
  可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):
Condition.wait([timeout]):  
  wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。
Condition.notify():
  唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。
Condition.notify_all()
Condition.notifyAll()
  唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

在这里采用threading.Condition类的方法:但是这样太麻烦,后面采用Queen的方式:

 1 #!/usr/bin/env python
 2 #----coding:utf-8----
 3 ##python 下对生产者和消费者模型的理解
 4
 5 import threading
 6 import random
 7 import time
 8
 9 lock=threading.Condition()
10
11 class Produce(threading.Thread):
12
13     def __init__(self,lock,product,filename):
14         self._lock=lock
15         self.product=product
16         self.file=filename
17         threading.Thread.__init__(self)
18     def run(self):
19         while True:
20             if self._lock.acquire():##判断是否得到锁,类似于Java中lock1.lock
21                 if (len(self.product)>100):
22                     self._lock.wait()
23                 else:
24                     ##打印现在product数字,同时将其中IO写入txt文档
25                     tmp=random.randint(0,10)
26                     self.product.append(tmp)
27
28                     print "add %d,product=%s: "%(tmp,str(self.product))
29
30                     ##通过IO口写入
31                     fp=open(self.file,‘a‘)
32                     fp.write("add %d, product = %s\n" %(tmp,str(self.product)))
33                     fp.close()
34                 self._lock.notify()
35                 self._lock.release()
36                 time.sleep(0.2)
37
38 class Consumer(threading.Thread):
39     def __init__(self,lock,product,filename):
40         self._lock = lock
41         self.product = product
42         self.file=filename
43         threading.Thread.__init__(self)
44
45     def run(self):
46         while True:
47             if self._lock.acquire():
48                 if len(self.product)== 0:
49                     self._lock.wait()
50                 else:
51                     tmp = self.product[0]
52                     del self.product[0]
53                     print ‘consum %d, product =%s‘%(tmp,str(self.product))
54                     fp=open(self.file,‘a‘)
55                     fp.write(‘consum %d, product = %s\n‘%(tmp,str(self.product)))
56                     fp.close()
57                 self._lock.notify()
58                 self._lock.release()
59                 time.sleep(0.1)
60
61
62
63
64
65 if __name__==‘__main__‘:
66     product=[]
67     ##假设product有五位:,消费者只有三位
68     for i in xrange(5):
69         p=Produce(lock,product,‘log_in.txt‘)
70         p.start()
71
72     for i in xrange(3):
73         T=Consumer(lock,product,‘log_in.txt‘)
74         T.start()
75
76     
时间: 2024-08-02 02:45:33

爬虫(五):生产者消费者方法的相关文章

进程_线程 之(五) --- 生产者消费者

同步锁 acquire([timeout])/release():  调用关联的锁的相应方法. wait([timeout]):   调用这个方法将使线程进入Condition的等待池等待通知,并释放锁.使用前线程必须已获得锁定,否则将抛出异常. notify():   调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池):其他线程仍然在等待池中.调用这个方法不会释放锁定.使用前线程必须已获得锁定,否则将抛出异常. notifyAll()

[Java] 多线程下生产者消费者问题的五种同步方法实现

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题. 生产者消费者模式的优点 - 解耦 - 支持并发 - 支持忙闲不均 解决方法可分为两类: (1)用信号量和锁机制实现生产者和消费者之间的同步: - wait() / notify()方法 - await() / signal()方法 - BlockingQueue阻塞队列方法 - Semaphore方法 (2)在生产者和消费者之间建立一个管道.(一般不使用,缓冲区不易控制.数据不易封装和传输) - PipedInputStream

多线程实现生产者消费者问题 详细注释 事件+临界区 信号量+临界区2种方法

生产者消费者问题:  该问题描述了两个共享固定大小缓冲区的线程--即所谓的"生产者"和"消费者"--在实际运行时会发生的问题.生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程.与此同时,消费者也在缓冲区消耗这些数据.该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据.具体我就不解释了   应该都懂 不懂请百度一下 我是用事件实现生产者消费者问题的同步  用临界区实现互斥    我的这个做法与经典做法不同 即用信号量

五、生产者消费者模型

1.生产者消费者模型作用和示例如下:1)通过平衡生产者的生产能力和消费者的消费能力来提升整个系统的运行效率 ,这是生产者消费者模型最重要的作用2)解耦,这是生产者消费者模型附带的作用,解耦意味着生产者和消费者之间的联系少,联系越少越可以独自发展而不需要收到相互的制约备注:对于生产者消费者模型的理解将在并发队列BlockingQueue章节进行说明,本章不做详细介绍. package threadLearning.productCustomerModel; /* wait/notify 机制:以资

线程安全的生产者消费者四种实现方法

问题描述 在IT技术面试过程中,我们经常会遇到生产者消费者问题(Producer-consumer problem), 这是多线程并发协作问题的经典案例.场景中包含三个对象,生产者(Producer),消费者(Consumer)以及一个固定大小的缓冲区(Buffer).生产者的主要作用是不断生成数据放到缓冲区,消费者则从缓冲区不断消耗数据.该问题的关键是如何线程安全的操作共享数据块,保证生产者线程和消费者线程可以正确的更新数据块,主要考虑 1. 生产者不会在缓冲区满时加入数据. 2. 消费者应当

Linux组件封装(五)一个生产者消费者问题示例

生产者消费者问题是计算机中一类重要的模型,主要描述的是:生产者往缓冲区中放入产品.消费者取走产品.生产者和消费者指的可以是线程也可以是进程. 生产者消费者问题的难点在于: 为了缓冲区数据的安全性,一次只允许一个线程进入缓冲区,它就是所谓的临界资源. 生产者往缓冲区放物品时,如果缓冲区已满,那么需要等待,一直到消费者取走产品为止. 消费者取走产品时,如果没有物品,需要等待,一直到有生产者放入为止. 第一个问题属于互斥问题,我们需要使用一把互斥锁,来实现对缓冲区的安全访问. 后两个属于同步问题,两类

进程间通信IPC---队列、生产者消费者模型、生产者消费者模型_joinableQueue(五)

#  队列 # 队列 先进先出# IPC# from multiprocessing import Queue# q = Queue(5)# q.put(1)# q.put(2)# q.put(3)# q.put(4)# q.put(5)# print(q.full()) # 队列是否满了,已满话再次放入会阻塞# print(q.get())# print(q.get())# print(q.get())# print(q.get())# print(q.get())# print(q.empt

Java 并发编程(四)阻塞队列和生产者-消费者模式

阻塞队列 阻塞队列提供了可阻塞的 put 和 take 方法,以及支持定时的 offer 和 poll 方法.如果队列已经满了,那么put方法将阻塞直到有空间可以用:如果队列为空,那么take方法将一直阻塞直到有元素可用.队列可以使有界的,也可以是无界的,无界队列永远都不会充满,因此无界队列上的put方法永远不会阻塞.一种常见的阻塞生产者-消费者模式就是线程池与工作队列的组合,在 Executor 任务执行框架中就体现了这种模式. 意义:该模式能简化开发过程,因为他消除了生产者和消费者类之间的代

【操作系统】经典的同步问题(生产者消费者问题, 哲学家进餐问题, 读写问题)

用专业术语来说, 进程是程序的一次动态执行.说简单点, 就是进程是系统中的某个任务.操作系统中有多个任务需要执行, 那么怎样执行才能使它们同步呢? 即如何让任务并发执行互不影响呢? 这就引出了进程同步中的经典问题: 生产者消费者问题, 哲学家进餐问题, 读写问题 生产者-消费者问题 有一群生产者进程在生产产品, 并将这些产品提供给消费者进程取消费. 为使生产者进程与消费者进程能并发进行, 在两者间设置了一个具有n个缓冲区的缓冲池, 生产者进程将其所生产的产品翻入缓冲区中, 消费者进程可从一个缓冲