python学习笔记——多线程同步问题


如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。

1 简单的线程同步。

  使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。如下:

import threading

import time

class mythread(threading.Thread):

    def__init__(self,threadname):

       threading.Thread.__init__(self,name=threadname)

    defrun(self):

       global x

       lock.acquire()

       for i in range(3):

           x=x+1

       time.sleep(2)

       print x

       lock.release()

lock=threading.RLock()

t1=[]

for i in range(10):

   t=mythread(str(i))

   t1.append(t)

x=0

for i in t1:

i.start()

运行结果如下:

>>> 3

6

9

12

15

18

21

24

27

30

 

>>> 

   而如果我们把acquire()和release()去掉,结果就不同了:

30303030303030303030

   这是因为每个线程执行后在打印出x之前都要休眠2秒钟,所以在这个过程中,每个线程都被执行了,所以等到休眠结束,打印出的X的值自然就是经过多次运算以后的X的值了。

而第一次,我们把全局变量X放到了acquire()和release()之间,python解释器每次回只允许一个线程对x进行操作,只有这个线程结束对其操作并且休眠结束打印出来以后,才允许下一个线程对x操作,所以输出的X是每次递增的,而且用时间也是比较长的。

 

2 使用条件变量保持线程同步

   Python的Condition对象提供了对复杂线程同步的支持,使用它可以在某些事件触发之后才处理数据,condition的方法有很多,看下面的例子:

用Condition来实现著名的生产者和消费者的关系:

import threading

class Producer(threading.Thread):

    def__init__(self,threadname):

       threading.Thread.__init__(self,name=threadname)

    defrun(self):

       global x

       con.acquire()

       if x==1000000:

           con.wait()

           pass

       else:

           for i in range(1000000):

               x=x+1

           con.notify()

       print x

       con.release()

 

class Consumer(threading.Thread):

    def__init__(self,threadname):

       threading.Thread.__init__(self,name=threadname)

    defrun(self):

       global x

       con.acquire()

       if x==0:

           con.wait()

           pass

       else:

           for i in range(1000000):

               x=x-1

           con.notify()

       print x

       con.release()

con=threading.Condition()

x=0

p=Producer('Producer')

c=Consumer('Consumer')

p.start()

c.start()

p.join()

c.join()

print x

 

结果如下:

>>>

1000000

0

0

>>> 

 

3 使用队列保持线程同步

   同样的例子,使用Queue可以实现多生产者和多消费者的先进先出的队列,每个生产者将数据依次存入队列,而每个消费者则依次从队列中取出数据,看下面的例子:

import threading

import time

import Queue

 

class Producer(threading.Thread):

    def__init__(self,threadname):

       threading.Thread.__init__(self,name=threadname)

    defrun(self):

       global queue

       queue.put(self.getName())

       print self.getName(),'put',self.getName(),'to queue'

 

class Consumer(threading.Thread):

    def__init__(self,threadname):

       threading.Thread.__init__(self,name=threadname)

    defrun(self):

       global queue

       print self.getName(),'get',self.getName(),'from queue'

 

queue=Queue.Queue()

plist=[]

clist=[]

for i in range(10):

   p=Producer('Producer'+str(i))

   plist.append(p)

for i in range(10):

   c=Consumer('Consumer'+str(i))

   clist.append(c)

 

for i in plist:

   i.start()

   i.join()

for i in clist:

   i.start()

   i.join()

   

看结果:

>>>

Producer0 put Producer0 to queue

Producer1 put Producer1 to queue

Producer2 put Producer2 to queue

Producer3 put Producer3 to queue

Producer4 put Producer4 to queue

Producer5 put Producer5 to queue

Producer6 put Producer6 to queue

Producer7 put Producer7 to queue

Producer8 put Producer8 to queue

Producer9 put Producer9 to queue

Consumer0 get Consumer0 from queue

Consumer1 get Consumer1 from queue

Consumer2 get Consumer2 from queue

Consumer3 get Consumer3 from queue

Consumer4 get Consumer4 from queue

Consumer5 get Consumer5 from queue

Consumer6 get Consumer6 from queue

Consumer7 get Consumer7 from queue

Consumer8 get Consumer8 from queue

Consumer9 get Consumer9 from queue


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值