Python 多线程threading学习
上节我们学习了threading.Thread和threading.Timer,这次我们继续来学习threading的接下来的内容:threading.Lock、threading.RLock、threading.Condition
我们先来学习下Lock的内容:
对于下面这个程序的执行,明显是有问题的,尤其是在多线程执行过程中
#encoding=gbk
import threading
import time
counter=0
class add_thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global counter
time.sleep(1)
counter += 1
print "%s,set counter:%s" %(self.name,counter)
if __name__ == "__main__":
for i in range(200):
thread = add_thread()
thread.start()
多执行几次,就会出现问题,如下面这个:
Thread-167,set counter:167Thread-169,set counter:168
Thread-168,set counter:169
这里看以看出来,全局资源counter被线程抢占的情况,问题 产生的原因就是没有控制多线程访问同一个资源,让线程的执行结果不可预料,这就是线程不安全的。这个方法的避免就是互斥锁了。
下面我们看下threading.Lock类:
A primitive lock is a synchronization primitive that is not owned by a particular thread when locked. In Python, it is currently the lowest level synchronization primitive available, implemented directly by the thread extension module.
按照描述,这个Lock是Thread的最低级别的同步实现,下面还有一段话:
A primitive lock is in one of two states, “locked” or “unlocked”. It is created in the unlocked state. It has two basic methods, acquire() and release(). When the state is unlocked, acquire() changes the state to locked and returns immediately. When the state is locked, acquire() blocks until a call to release() in another thread changes it to unlocked, then the acquire() call resets it to locked and returns. The release() method should only be called in the locked state; it changes the state to unlocked and returns immediately. If an attempt is made to release an unlocked lock, a RuntimeError will be raised.
简单的说就是同一时刻只能有一把锁,并且锁的状态互斥。锁上加锁等待,无锁解锁异常,无锁加锁和锁上解锁都是正常的。
加锁后的代码:
#encoding=gbk
import threading
import time
counter=0
mutex=threading.Lock()
class add_thread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global counter,mutex
time.sleep(1)
if mutex.acquire():
counter += 1
print "%s,set counter:%s" %(self.name,counter)
mutex.release()
if __name__ == "__main__":
for i in range(200):
thread = add_thread()
thread.start()
多运行几次,运行结果都是正常的。
现在有个额外的考虑:
有两个线程互相等待对方释放资源,这种情况下死锁怎么办?
如果线程持有对象锁,又需要获取锁,这种锁嵌套怎么办?
第一个问题需要正确有序的分配资源,有名的算法是银行家算法,这个不是我们本节的重点。后者这种重复获取情况,python给我们提供了一种可重入锁,threading.RLock的官方声明如下:
A reentrant lock is a synchronization primitive that may be acquired multiple times by the same thread. Internally, it uses the concepts of “owning thread” and “recursion level” in addition to the locked/unlocked state used by primitive locks. In the locked state, some thread owns the lock; in the unlocked state, no thread owns it.
这个Rlock的重点是acquire方法和release方法必须成对出现,否则就会出问题。
上面的Lock和RLock能够解决一部分线程对于公共资源的访问问题,不过线程编程模型不可能这么简单,如果出现资源出现动态变化的情况,线程需要根据资源的状态进行操作,这个又该怎么做?Python同样提供了对于复杂线程问题的同步支持,threading.Condiion
A condition variable is always associated with some kind of lock; this can be passed in or one will be created by default. (Passing one in is useful when several condition variables must share the same lock.)
Condition成为条件变量,除了提供acquire方法和release方法外,还提供了notify方法、wait方法和notifyAll方法。这个可以使Condition根据条件进行判断。如果不满足条件wait,在满足条件时执行动作,执行完成后notify其它线程。重复这个过程,解决复杂的同步过程。其中最为典型的就是生产者-消费者模型。下面我们用Condition同步实现这个模型。
#encoding=gbk
import threading
import time
condition = threading.Condition()
products = 0
class Producer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products < 10:
products += 1;
print "Producer(%s):deliver one, now products:%s" %(self.name, products)
condition.notify()
else:
print "Producer(%s):already 10, now products:%s" %(self.name, products)
condition.wait();
condition.release()
time.sleep(2)
class Consumer(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global condition, products
while True:
if condition.acquire():
if products > 1:
products -= 1
print "Consumer(%s):consume one, products:%s" %(self.name, products)
condition.notify()
else:
print "Consumer(%s):only 1, stop consume" %(self.name)
condition.wait();
condition.release()
time.sleep(2)
if __name__ == "__main__":
for p in range(0, 2):
p = Producer()
p.start()
for c in range(0, 10):
c = Consumer()
c.start()
看下执行结果,重点是分析condition在Producer-Consumer模型中的作用。
下节我们继续学习threading的其它内容
分享到:
相关推荐
python多线程-threading模块.pdf
python多线程-threading模块.docx
1、多线程的理解 多进程和多线程都可以执行多个任务,线程是进程的一部分。...2、Python多线程创建 在Python中,同样可以实现多线程,有两个标准模块thread和threading,不过我们主要使用 更高级的threading模块。
python多线程threading.doc
threading模块API是面向对象的,其中最重要的是线程类Thread,此外还有很多线程相关函数,这些函数常用的有:返回当前处于活动状态的线程数。例如:#
python 08、多任务编程多线程 3-1_进程间通信、同步互斥、threading线程_Day03_AM.mp4
Python进程Process模块-Python零基础⼊门教程 Python进程Process模块-Python零基础⼊门教程 ⽬录 ⼀.... ⼆.Python 进程 Process 模块 ⼆.Python 进程 Process 模块 对于线程操作可以⽤ threading 模块,那么对于进程的
Python多线程编程文档说明 多进程编程 一、 multiprocessing 模块 1. multiprocessing 模块提供了多进程编程的能力 它的API非常类似于 threading 模块,但是也提供了一些threading 模块不具有的能力 相比于线程,它...
Python多线程编程方式2 threading库的介绍源码
threading模块和thread模块练习
python基础_31_Python_threading_1_什么是多线程_(教学教程tutorial)
Python多线程套接字编程全文共10页,当前为第1页。Python多线程套接字编程全文共10页,当前为第1页。Python多线程套接字编程 Python多线程套接字编程全文共10页,当前为第1页。 Python多线程套接字编程全文共10页,...
Python多线程爬虫 Python多线程模块 在Python中可使用的多线程模块主要有两个,thread和threading模块。 threading模块允许创建和管理线程,提供了更多的同步原语。threading模块中最常用的类是Thread。 Python多...
主要讲述Python多线程编程,主要讲述的thread库,threading库,Queue库等实现多线程编程
调用类中get_target()方法即可开始扫描,可在port_list.txt中自定义扫描端口,算是一个工具模块,调用方便,自定义线程类支持可调节线程数量,可根据自己需要调整,由于是相当于重构默认的threading模块,编写了一个...
现在这个例子添加了多线程 之前的例子有解释:https://blog.csdn.net/y363893017/article/details/105676878 大家可以自己去看,仅供学习,提供思路。 以下是我自己电脑上的截图 两个线程上传 上传完一个后 服务端...
python 多线程的同步机制 以python2例程的方式讲解了python 多线程的同步 常用的方法,主要是锁、条件同步、队列 多线程的同步 多线程情况下最常见的问题之一:数据共享; 当多个线程都要去修改某一个共享数据...
Python_threading_6_锁_lock_(多线程_教学教程tutorial)
本文实例为大家分享了python多线程实现TCP服务端的具体代码,供大家参考,具体内容如下 需求 1.创建一个TCP服务器接收服务端发送的信息并给予答复 2.以多线程方式实现接收客户端信息 3.间客户端发送的信息解码...
python多线程详解目录python多线程详解一、线程介绍什么是线程为什么要使用多线程二、线程实现 threading模块 自定义线程 守护线程 主线程等待子