Archive for the 'Python' Category
Python线程编程(三)同步队列
我们经常会采用生产者/消费者关系的两个线程来处理一个共享缓冲区的数据。
例如一个生产者线程接受用户数据放入一个共享缓冲区里,等待一个消费者线程对
数据取出处理。但是如果缓冲区的太小而生产者和消费者两个异步线程的速度不同
时,容易出现一个线程等待另一个情况。为了尽可能的缩短共享资源并以相同速度
工作的各线程的等待时间,我们可以使用一个“队列”来提供额外的缓冲区。
此文章转自:
http://users.ir-lab.org/~bill_lang/blog10/archives/001837.html
此篇为其第三部分
看到URL中包含~bill_lang,知道这是bill_lang的个人地方,由于担心
好东西说不定那天就没了,所以全文转载过来。但是不知道bill_lang从
什么地方转载过来的,没法给出原文的链接了!
创建一个“队列”对象
import Queue
myqueue = Queue.Queue(maxsize = 10)
Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过
Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队
列长度无限。
将一个值放入队列中
myqueue.put(10)
调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为
必需的,为插入项目的值;第二个block为可选参数,默认为1。如果队列当前为空
且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为
0,put方法将引发Full异常。
将一个值从队列中取出
- myqueue.get()
调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为
1。如果队列为空且block为1,get()就使调用线程暂停,直至有项目可用。如果
block为0,队列将引发Empty异常。
我们用一个例子来展示如何使用Queue
- # queue_example.py
- from Queue import Queue
- import threading
- import random
- import time
- # Producer thread
- class Producer(threading.Thread):
- def __init__(self, threadname, queue):
- threading.Thread.__init__(self, name = threadname)
- self.sharedata = queue
- def run(self):
- for i in range(20):
- print self.getName(),'adding',i,'to queue'
- self.sharedata.put(i)
- time.sleep(random.randrange(10)/10.0)
- print self.getName(),'Finished'
- # Consumer thread
- class Consumer(threading.Thread):
- def __init__(self, threadname, queue):
- threading.Thread.__init__(self, name = threadname)
- self.sharedata = queue
- def run(self):
- for i in range(20):
- print self.getName(),'got a value:',self.sharedata.get()
- time.sleep(random.randrange(10)/10.0)
- print self.getName(),'Finished'
- # Main thread
- def main():
- queue = Queue()
- producer = Producer('Producer', queue)
- consumer = Consumer('Consumer', queue)
- print 'Starting threads ...'
- producer.start()
- consumer.start()
- producer.join()
- consumer.join()
- print 'All threads have terminated.'
- if __name__ == '__main__':
- main()
示例代码中实现了两个类:生产者类Producer和消费者类Consumer。前者在一个随
机的时间内放入一个值到队列queue中然后显示出来,后者在一定随机的时间内从
队列queue中取出一个值并显示出来。
Python线程编程(二)简单的线程同步
Python线程编程(二)简单的线程同步
多个执行线程经常要共享数据,如果仅仅读取共享数据还好,但是如果多个线
程要修改共享数据的话就可能出现无法预料的结果。
假如两个线程对象t1和t2都要对数值num=0进行增1运算,那么t1和t2都各对
num修改10次的话,那么num最终的结果应该为20。但是如果当t1取得num的值时
(假如此时num为0),系统把t1调度为“sleeping”状态,而此时t2转换为
“running”状态,此时t2获得的num的值也为0,然后他把num+1的值1赋给num。系统
又把t2转化为“sleeping”状态,t1为“running”状态,由于t1已经得到num值为0,
所以他也把num+1的值赋给了num为1。本来是2次增1运行,结果却是num只增了1
次。类似这样的情况在多线程同时执行的时候是有可能发生的。所以为了防止这类
情况的出现就要使用线程同步机制。
最简单的同步机制就是“锁”
锁对象用threading.RLock类创建
- mylock = threading.RLock()
如何使用锁来同步线程呢?线程可以使用锁的acquire() (获得)方法,这样
锁就进入“locked”状态。每次只有一个线程可以获得锁。如果当另一个线程试图获
得这个锁的时候,就会被系统变为“blocked”状态,直到那个拥有锁的线程调用锁
的release() (释放)方法,这样锁就会进入“unlocked”状态。“blocked”状态的
线程就会收到一个通知,并有权利获得锁。如果多个线程处于“blocked”状态,所
有线程都会先解除“blocked”状态,然后系统选择一个线程来获得锁,其他的线程
继续沉默(“blocked”)。
- import threading
- mylock = threading.RLock()
- class mythread(threading.Thread)
- ...
- def run(self ...):
- ... #此处 不可以 放置修改共享数据的代码
- mylock.acquire()
- ... #此处 可以 放置修改共享数据的代码
- mylock.release()
- ... #此处 不可以 放置修改共享数据的代码
我们把修改共享数据的代码称为“临界区”,必须将所有“临界区”都封闭在同一
锁对象的acquire()和release()方法调用之间。
锁只能提供最基本的同步级别。有时需要更复杂的线程同步,例如只在发生某
些事件时才访问一个临界区(例如当某个数值改变时)。这就要使用“条件变量”。
条件变量用threading.Condition类创建
- mycondition = threading.Condition()
条件变量是如何工作的呢?首先一个线程成功获得一个条件变量后,调用此条
件变量的wait()方法会导致这个线程释放这个锁,并进入“blocked”状态,直到另
一个线程调用同一个条件变量的notify()方法来唤醒那个进入“blocked”状态的线
程。如果调用这个条件变量的notifyAll()方法的话就会唤醒所有的在等待的线程。
如果程序或者线程永远处于“blocked”状态的话,就会发生死锁。所以如果使
用了锁、条件变量等同步机制的话,一定要注意仔细检查,防止死锁情况的发生。
对于可能产生异常的临界区要使用异常处理机制中的finally子句来保证释放锁。
等待一个条件变量的线程必须用notify()方法显式的唤醒,否则就永远沉默。保证
每一个wait()方法调用都有一个相对应的notify()调用,当然也可以调用
notifyAll()方法以防万一。
Python多线程编程(一) 线程对象
此文章转自:
http://users.ir-lab.org/~bill_lang/blog10/archives/001837.html
看到URL中包含~bill_lang,知道这是bill_lang的个人地方,由于担心
好东西说不定那天就没了,所以全文转载过来。但是不知道bill_lang从
什么地方转载过来的
Python多线程编程[Zz]
Python线程编程(一)线程对象
我们在做软件开发的时候很多要用到多线程技术。例如如果做一个下载软件象
flashget就要用到、象在线视频工具realplayer也要用到因为要同时下载media
stream还要播放。其实例子是很多的。
线程相对进程来说是“轻量级”的,操作系统用较少的资源创建和管理线程。程序中
的线程在相同的内存空间中执行,并共享许多相同的资源。
在python中如何创建一个线程对象
如果你要创建一个线程对象,很简单,只要你的类继承threading.Thread,然后在
__init__里首先调用threading.Thread的__init__方法即可
- import threading
- class mythread(threading.Thread):
- def __init__(self, threadname):
- threading.Thread.__init__(self, name = threadname)
- ....
这才仅仅是个空线程,我可不是要他拉空车的,他可得给我干点实在活。很简单,
重写类的run()方法即可,把你要在线程执行时做的事情都放到里面
- import threading
- import time
- class mythread(threading.Thread):
- def __init__(...):
- ....
- def run(self):
- for i in range(10):
- print self.getName, i
- time.sleep(1)
以上代码我们让这个线程在执行之后每隔1秒输出一次信息到屏幕,10次后结束
getName()是threading.Thread类的一个方法,用来获得这个线程对象的name。还
有一个方法setName()当然就是来设置这个线程对象的name的了。
如果要创建一个线程,首先就要先创建一个线程对象
- mythread1 = mythread('mythread 1')
一个线程对象被创建后,他就处于“born”(诞生状态)
如何让这个线程对象开始运行呢?只要调用线程对象的start()方法即可
- mythread1.start()
现在线程就处于“ready”状态或者也称为“runnable”状态。
奇怪吗?不是已经start了吗?为什么不称为“running”状态呢?其实是有原因的。
因为我们的计算机一般是不具有真正并行处理能力的。我们所谓的多线程只是把时
间分成片段,然后隔一个时间段就让一个线程执行一下,然后进入“sleeping ”状
态,然后唤醒另一个在“sleeping”的线程,如此循环runnable->sleeping->
runnable… ,只是因为计算机执行速度很快,而时间片段间隔很小,我们感受不
到,以为是同时进行的。所以说一个线程在start了之后只是处在了可以运行的状
态,他什么时候运行还是由系统来进行调度的。
那一个线程什么时候会“dead”呢?一般来说当线程对象的run方法执行结束或者在
执行中抛出异常的话,那么这个线程就会结束了。系统会自动对“dead”状态线程进
行清理。
如果一个线程t1在执行的过程中需要等待另一个线程t2执行结束后才能运行的话那
就可以在t1在调用t2的join()方法
- ....
- def t1(...):
- ...
- t2.join()
- ...
这样t1在执行到t2.join()语句后就会等待t2结束后才会继续运行。
但是假如t1是个死循环的话那么等待就没有意义了,那怎么办呢?可以在调用t2的
join()方法的时候给一个浮点数做超时参数,这样这个线程就不会等到花儿也谢了
了。我等你10s,你不回来我还不允许我改嫁啊?:)
- def t1(...):
- ...
- t2.join(10)
- ...
如果一个进程的主线程运行完毕而子线程还在执行的话,那么进程就不会退出,直
到所有子线程结束为止,如何让主线程结束的时候其他子线程也乖乖的跟老大撤退
呢?那就要把那些不听话的人设置为听话的小弟,使用线程对象的setDaemon()方
法,参数为bool型。True的话就代表你要听话,我老大(主线程)扯呼,你也要跟
着撤,不能拖后腿。如果是False的话就不用那么听话了,老大允许你们将在外军
命有所不受的。需要注意的是setDaemon()方法必须在线程对象没有调用start()方
法之前调用,否则没效果。
- t1 = mythread('t1')
- print t1.getName(),t1.isDaemon()
- t1.setDaemon(True)
- print t1.getName(),t1.isDaemon()
- t1.start()
- print 'main thread exit'
当执行到 print ‘main thread exit’ 后,主线程就退出了,当然t1这个线程也跟
着结束了。但是如果不使用t1线程对象的setDaemon()方法的话,即便主线程结束
了,还要等待t1线程自己结束才能退出进程。isDaemon()是用来获得一个线程对象
的Daemonflag状态的。
如何来获得与线程有关的信息呢?
获得当前正在运行的线程的引用
- running = threading.currentThread()
获得当前所有活动对象(即run方法开始但是未终止的任何线程)的一个列表
- threadlist = threading.enumerate()
获得这个列表的长度
- threadcount = threading.activeCount()
查看一个线程对象的状态调用这个线程对象的isAlive()方法,返回1代表处于
“runnable”状态且没有“dead”
- threadflag = threading.isAlive()
shell下调试Django的方便小toolkit
在调试的时候,有时候shell下面是很方便的。 除了manage.py shell之外,下面这几行代码可以帮我们不少忙。
- #shell.py
- import os
- import sys
- os.environ['DJANGO_SETTINGS_MODULE'] = "app.settings"
- sys.path.append(os.getcwd()) #shell.py 和其他module的路径有可能要修改
- from app.mymod.models import mymod
这样 就可以调试mymod了!比较方便! :D 其实说白了就是那个’DJANGO_SETTINGS_MODULE’环境变量没有设置,设置了之后就好了! 后面的from app.mymod.models import mymod是为了方便,免得每次调试都输入这些import。
保存/删除前后的额外动作
在Django中,常常会出现这样的情况: 在保存一个对象到数据库中或者从数据库把该对象删除的时候,希望可以执行另外一些附加的操作,
比如:
- class Place(models.Model):
- name = models.CharField(maxlength=50)
- address = models.CharField(maxlength=80)
- def save (self):
- self.name = 'hackgou'
- print "Before save"
- super(Place, self).save() #call the 'real' save() method
- print "After save"
- def delete (self):
- self.name = "test"
- super(Place,self).save() #这是在删除么 :P
- def __str__(self):
- return "%s the place" % self.name
- >>from djangoTest.oneToOne.models import *
- >>>l = Place(None,"Gavin","sichuang")
- >>>l
- >>>l.save()
- Before
- save
- After save
- >>> l.name
- 'hackgou'
- >>> l = Place.objects.get(name__startswith="QQ")
- >>>l
- >>> l.delete()
- >>> l.name
- 'test'
- >>>
这好像在玩魔术。
其实这和以前版本中的_save()以及meta中定义_save()来重载Model
的save()一样,只是现在名字和Model中的一样,更加像真正的重载了!
