python——线程相关

使用python的threading中的Thread

下面是两种基本的实现线程的方式:

第一种方式————

#coding=utf-8

"""
thread的第一种声明及调用方式
"""

from threading import Thread
import time

def func():
    while True:
        print time.ctime()
        time.sleep(1)

def func1():
    while True:
        print "func1", time.ctime()
        time.sleep(2)

#将要执行的方法作为参数传给Thread的构造方法
    
t = Thread(target=func)
t.start()

t1 = Thread(target=func1)
t1.start()

第二种方式————

#coding=utf-8

"""
thread的第二种声明及调用方法
"""

import time
from threading import Thread
from time import sleep

#从Thread继承,并重写run()
class myThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)
    
    def run(self):
        while True:
            print self.getName() + " " + time.ctime()
            time.sleep(1)
            
t = myThread("thread_1")
t.start()

t1 = myThread("thread_2")
t1.start()
            

接下来是:join和setDaemon的方法调用及具体区别:

join的方法调用:

#coding=utf-8

"""
join方法的含义是:存在A主线程,B子线程,在A主线程中生成了一个子线程B,
如果子线程B调用了join方法,则主线程需要等待子线程操作结束,才能够继续往下执行,主线程会被阻塞
"""
import time
from threading import Thread

class myThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name = threadname)
    
    def run(self):
        time.sleep(10)
        print self.getName() + " " + time.ctime()
        
    
def mainfunc():
    for i in range(5):
        print i    
    
if __name__ == "__main__":
    t = myThread("childthread")
    t.start()
    #增加join方法的调用,则程序运行时的表现是:先子线程(会先sleep 10s,之后打印子线程的内容),再运行主线程中的打印从0到4的逻辑
    #不增加join方法的调用,则程序运行时的表现是:会先走主线程的打印从0到4的逻辑,之后子线程(sleep 10s,再打印子线程中的内容),但其实这里就是没有等待子线程
#     t.join()
    mainfunc()

setDaemon方法的调用:

#coding=utf-8

"""
daemon方法的含义是:存在主线程A,和子线程B,子线程B是从主线程A中生成的
如果设置子线程B为daemon即守护进程,则主线程A不存在的话,子线程B就退出
如果没有设置子线程B为daemon,则主线程A结束运行退出之后,子线程B也不退出
"""

import time
from threading import Thread

class myThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)
    
    def run(self):
        time.sleep(10)
        print self.getName() + " " + time.ctime()
    
def mainfunc():
    for i in range(5):
        print i

if __name__ == "__main__":
    t = myThread("zixiancheng")
    #不设置子线程为守护进程,则主线程退出,子线程继续运行
    #设置子线程为守护进程,则主线程退出,子线程直接退出
    #并且,需要在start之前调用setDaemon
#     t.setDaemon(True)
    t.start()
    mainfunc()
    

 接下来是线程同步相关的内容:

首先是没有线程同步机制的情况下,多个线程同时操作一个公共数据:

代码如下:

#coding=utf-8

"""
@function: test Thread的Lock
@author: LiXia
@date: 2017-0303
"""

"""
所有的锁都是为了在线程之间进行通信
例如对一个公共变量进行操作,此例子为没有使用线程同步机制对公共变量进行操作
"""

from threading import Thread
import time

data = 0

class myThread(Thread):
    def __init__(self):
        Thread.__init__(self)
    
    def run(self):
        global data
        time.sleep(1)
        data += 1
        print self.getName() + " data: " + str(data)
            

if __name__ == "__main__":
    for i in range(5):
        t = myThread()
        t.start()

运行结果见下方:

为了能够对公共操作的数据,在特定逻辑内保持一致,需要保证在该逻辑内,只有单个线程可以操作,其他线程需要等待该线程处理结束才可以。

所以下面是关于python线程同步机制提供的指令:

1、Lock: 

但是将以上代码中增加上lock处理,注意一定要增加在对公共数据的逻辑判断和处理的前面和后面,所以这里必须添加到while判断之前,释放锁需要在输出操作结束之后添加

即:

#coding=utf-8

"""
所有的锁都是为了在线程之间进行通信
例如对一个公共变量进行操作
"""

from threading import Thread
import threading
import time

data = 0
lock = threading.Lock()

class myThread(Thread):
    def __init__(self):
        Thread.__init__(self)
    
    def run(self):
        global data
        if lock.acquire():
            time.sleep(1)
            data += 1
            print self.getName() + " data: " + str(data)
        lock.release()
            

if __name__ == "__main__":
    for i in range(5):
        t = myThread()
        t.start()

运行结果见下方:

 2、RLock

代码如下:

#coding=utf-8

"""
通过RLock(可重入锁)进行线程间的安全通信,RLock为可重入锁,即线程在拥有RLock之后可以继续acquire(),只要保证acquire()次数与
release()次数一致即可;
继续对公共变量进行操作
"""

from threading import Thread
import threading
import time

rlock = threading.RLock()
data = 0

class myThread(Thread):
    def __init__(self):
        Thread.__init__(self)
    
    def run(self):
        global data
        if rlock.acquire():
            time.sleep(1)
            data += 1
            print self.getName() + " data:" + str(data)
            
            if rlock.acquire():
                time.sleep(1)
                data -= 1
                print self.getName() + " data:" + str(data)
                rlock.release() 
            rlock.release()
            
    
if __name__ == "__main__":
    for i in range(5):
        t = myThread()
        t.start()

运行结果:

3、Condition

Condition就是条件变量,condition通常与一个锁关联。

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

#coding=utf-8

"""
以最经典的生产者和消费者的问题为例,两者需要针对一个公共的数据区域做操作,并且两端需要进行通信
生产者在生产之前,需要先占领地盘,然后开始生产,生产结束通知消费者来取;
消费者在消费的时候,也需要先占领地盘,然后开始消费,消费结束通知生产者继续生产;
当然还有多个生产者和消费者的情况,会更加复杂,可以用python的Queue来实现
"""

from threading import Thread
import threading
import time
import random

product = []
con = threading.Condition()    #得到一个Condition的对象

#生产者线程
class producerThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)
    
    def run(self):
        global product
        if con.acquire():
            while True:
                r = random.randint(0, 20)
                product.append(r)
                print "product len and product: ", self.getName(), product
                con.notify()
                con.wait()
#                 time.sleep(2)

#消费者线程    
class consumerThread(Thread):
    def __init__(self, threadname):
        Thread.__init__(self, name=threadname)
    
    def run(self):
        global product
        if con.acquire():
            while True:
                if product != []:
                    product.pop()
                    print "consumer len and product: ", self.getName(), product
                    con.notify()
                con.wait()
                time.sleep(2)
        
if __name__ == "__main__":
    t1 = producerThread("producer")
    t2 = consumerThread("consumer")
    
    t1.start()
    t2.start()
    

运行结果如下:

 4、对多个生产者消费者支持的很好的Queue

Queue是什么?Queue实现了多生产者-多消费者的队列形式,分别包含先入先出(默认)FIFO、后进先出LIFO、以及优先级队列PriorityQueue(优先级低的先出)

Queue模块的class及exception:

#coding=utf-8

"""
Queue的类和异常
"""

import Queue

q = Queue.Queue(maxsize = 0)    #FIFO的Queue,maxsize即Queue的size值,maxsize≤0表示无size限制

lq = Queue.LifoQueue(maxsize = 0) #LIFO的Queue,先进后出,maxsiz的含义同上

pq = Queue.PriorityQueue(maxsize = 0) #优先级Queue,优先级低的先出,maxsize的含义同上

Queue.Empty()  #当Queue的对象为空时,使用非阻塞get时会抛出异常

Queue.Full() #当Queue的对象已满时,使用非阻塞put时会抛出异常

Queue的对象:

Queue(Queue、LifoQueue、PriorityQueue)的对象提供的公共方法如下:

#coding=utf-8

"""
Queue(Queue、LifoQueue、PriorityQueue)的对象的公共方法
"""

import Queue

q = Queue.Queue()

q.qsize()   #获取Queue的大小
q.empty()   #是否为空,是则返回True,否则返回False
q.full()   #是否已满,是则返回True,否则返回False
q.put(item[, block[, timeout]])    #put元素到Queue中,可选参数block默认值为True,timeout默认值为None,即为阻塞方法,
#接上,若timeout为正值,则代表会阻塞timeout的时长之后引发一个full的异常(如果已满)
q.put_nowait(item) #相当于q.put(item, False)
q.get([block[, timeout]])  #get元素到Queue中,可选参数block默认值为True,timeout默认值为None,即为阻塞方法,
#接上,若timeout为正数,则代表会则色timeouu的时长之后会引发一个empty的异常(如果为空)
q.get_nowait() #相当于q.get(False)
q.task_done() #用在Queue的消费者模式下,即用在Queue.get()方法之后,通过Queue.task_done()告诉Queue当前任务完成
#如果当前join正在阻塞,则它将在所有item都被处理之后恢复
q.join() #会保持阻塞直到队列中的所有item都会处理
#接上,未完成的task数目会增加当一个item被add到Queue中,未完成的task数目会降低,每当消费者线程调用task_done来表示所有的
#接上,work都完成了,当未完成的数目降低到0时,join就自动取消阻塞了

Queue的主要用法是什么?

看一下Queue的源码实现,然后在另一篇博客中更新一下。

#coding=utf-8

"""
理解Queue的用法,理解Queue衍生出来的不同的class
"""

from Queue import Queue
from threading import Thread
import time
import random

q = Queue()

class producerQueue(Thread):
    def __init__(self, queue):
        Thread.__init__(self)
        self.queue = queue
    
    def run(self):
        while True:
            r = random.randint(0, 99)
            self.queue.put(r)
            print self.getName() + "produce " + str(r)
            time.sleep(1)
    
class consumerQueue(Thread):
    def __init__(self, queue):
        Thread.__init__(self)
        self.queue = queue
    
    def run(self):
        while True:
            r = self.queue.get()
            print self.getName() + "consume " + str(r)
            time.sleep(3)
            self.queue.task_done()
    
if __name__ == "__main__":
    threads = []
    for i in range(5):
        t = producerQueue(q)
        t.start()
#         threads.append(t)
     
    for i in range(3):
        t = consumerQueue(q)
        t.start()
#         threads.append(t)
     
    q.join()

之后得到的结果如下:

原文地址:https://www.cnblogs.com/keke-xiaoxiami/p/6492423.html