python3 threading thread 模块学习

时间:2023-01-22 20:40:03

转自:python3 threading thread 模块学习,保存在此以学习。

概述:

      <一>
Thread 类描绘了一个单独运行的控制线程活动,我们有两种方式指定这种活动,通过一个可调用对象的构造函数,或者通过覆盖子类run()方法。没有其他的方法应在子类中重写。换句话说,只有推翻这个类的__init__()和run()方法。
        一旦Thread这个对象被创建,这个对象的活动必须通过 thread 的start()方法启动。这将唤起run()方法在单独的线程控制。
        一旦线程的活动开始,这个线程的状态就是“alive”。当run()方法结束时才会结束“alive“状态。我们也可以直接运行 is_alive()方法判断这个进程的状态时"alive"
        一个线程可以调用另一个线程的join()方法。这种叫做阻塞调用线程,直到其join()方法叫做线程终止。
       一个线程的名字是通过构造器传递的,也可以通过name属性修改或者读取。
        一个线程可以标记为守护线程(daemon thread),这种被标记的线程时当python程序退出时它才退出。它的最初的值时当线程被创建时继承下来的。 这个标志可以通过daemon 或者daemone constructor变量设定。
        提示:daemon thread 是当程序关闭的时候立即被中断的。它时不会被适宜的释放。 如果你想让你的线程适宜的停止。可以让它non-daemonic 或者用一些适当的信号机制。
       有可能存在'dummy thread objects'(哑线程对象)被创建。这些线程对应于'alien threads'(外部线程),它们在Python的线程模型之外被启动,像直接从C语言代码中启动。哑线程对象只有有限的功能,它们总是被认为是活动的,守护线程,不能使用join()方法。它们从不能被删除,它无法监测到外部线程的中止。


Thread 中常用的方法和变量:
1.start()
启动线程活动。
2.run()
这个方法描述线程的活动,我们可以在子类中覆盖这个方法。
3.join()
    python的Thread类中还提供了join()方法,使得一个线程可以等待另一个线程执行结束后再继续运行。这个方法还可以设定一个timeout参数,避免无休止的等待。因为两个线程顺序完成,看起来象一个线程,所以称为线程的合并.
      通过传给join一个参数来设置超时,也就是超过指定时间join就不在阻塞进程。而在实际应用测试的时候发现并不是所有的线程在超时时间内都结束的,而是顺序执行检验是否在time_out时间内超时,例如,超时时间设置成2s,前面一个线程在没有完成的情况下,后面线程执行join会从上一个线程结束时间起再设置2s的超时。
4.name()
5.getname(0
6.setname()
7.ident()
8.is_alive()
9.daemon
一个布尔值,指示是否该线程是damemon thread(TRUE)或不(假)。这之前必须设置start()叫,否则运行时出错了。它的初始值是从创建线程继承;主线程不是一个守护线程,因此在守护=假主线程默认创建的所有线程。
整个Python程序退出时没有活着的非守护线程离开。
10.isDaemon()
11. setDaemon()

——————————————————————————————————————-————
——————————————————————————————————————————
<二> threading
threading 是比_thread 更高级的模块
方法:

    class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

        这个构造函数通常会用一些关键字参数,下面我们了解下这些关键字:
        group :这个变量作为保留变量,是为了以后扩展用的,暂时可以不用考虑。
        target: 是通过run()方法调用的可调用对象。默认为无,这意味着什么都不做。
        name:线程的名字。默认情况下,一个唯一的名称是”thread-n”,的形式,其中n是一个小的十进制数。
         args:元组参数,为target所调用的。
        kwargs:关键字参数的字典,为target所调用的。
        daemon: 设置daemon是否daemon 如果没有显示设置,daemon的属性时从当前线程继承。
      如果子类重写此构造函数,它必须确保在做别的事情之前调用基类的构造函数(thread.__init__()。


这模块定义了如下的方法

1,threading.active_aount()
这个函数返回当前线程的个数,这个程序的值也等于 列表enumerate()
的长度。
2.current_thread()
返回当前的线程对象。如果调用的线程不是通过threading 这个模块创建的,那么返回的是一个有限功能的dummy thread objects'(哑线程对象。
3.threading.get_ident()
返回当先线程的索引,这个索引是一个非零的整数。
4.threading.enumereate()
返回当前运行线程的列表。这个列表包含dummy thread objects'(哑线程对象,daemon thread'(守护线程),和那些主线程。这些线程的状态可能时已经运行的,还没有运行的。
5.threading.main_thread()
返回主线程,正常情况下,主线程就是python 解释器运行时开始的那个线程。
6,threading.settrace(func)
当开始调用threading 模块的时候设定 跟踪函数(trace function ),
7,threading.setpeofile()
 设定 profile function

8,threading.stack_size(【size】)
返回创建新线程时线程堆的大小。可选的数值size用于随后创建线程时使用,这个数字必须是零,或者大于32768(32kb)的整数。在未允许的情况下改变线程堆的大小会唤醒Runtimerror。如果这个线程堆的大小是无效的,那么会唤醒ValueError错误,并且线程堆的大小将不会设定。 32kb这个size是最小允许的线程堆大小,这样就可以保证线程堆有足够的大小在python解释器中安全的运行。有些平台对于线程堆的大小有特殊的限制。

这个模块也定义了一些常量。

threading.TIMEOT_,MAX

THREAD-LOCAK DATA

一,
——————
class threading.Sempaphore(value = 1) --限制资源的并发访问。
       semaphore 是一个内部的计数器,它会随着acquire()的请求减小,也会随着release()的释放增加。这个计数器的值不会小于零,当acquier() 发现计数器的值为0时,那么当前对象会等待直到其他对象release()为止。
   acquier(blocking = True ,timeout = None)
   release()
——————
class threading.Timer(interval,function,args = None ,kwargs = None)
    创建一个时间对象,设定一个函数于多长时间后运行。
   Timer.start()
   Timer.cancel()
——————
class.threading.Barrier(parties,action = None ,timeout = None)
   wait(timeout = None)
    这个类对那些固定数量的,需要相互等待的线程。提供了一个简单的同步机制。
    reset()
    abort()
    parties
    n_waiting
    broken


 二 ,Lock Objects
 
          primitive lock 有两种状态 unlock 和 lock,它有两种基本的方法,acpuire()和release(),当状态为unllocked时,调用acquire()方法会将状态改变为locked ,并立刻得到返回。当状态为locked时,acquire()方法直到另一个线程调用release()方法将状态改为unlocked,此时才会将状态设为locked并返回。而realease()方法只会被locked状态所调用, 他会将转台改为unlocked()并且立刻返回。将realease作用unlocked的lock时,将会抛出Runtimerror .

 两个方法 :
        acquier(blocking = True,timeout = -1)
        release()

#lock = threading.Lock()
#lock.acquire()
#locke.release()

三, RLock Objects( 如果同一个线程的不同代码需要“重新获得“锁,再这种情况下则需要使用RLock)
        class thread.RLock
 
四,Condition Objects
        使用Condition对象可以在某些事件触发或者达到特定的条件后才处理数据,Condition除了具有Lock对象的acquire方法和release方法外,还有wait方法、notify方法、notifyAll方法等用于条件处理。

threading.Condition([lock]):创建一个condition,支持从外界引用一个Lock对象(适用于多个condtion共用一个Lock的情况),默认是创建一个新的Lock对象。

acquire()/release():获得/释放 Lock

wait([timeout]):线程挂起,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。调用wait()会释放Lock,直至该线程被Notify()、NotifyAll()或者超时线程又重新获得Lock.

notify(n=1):通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notifhri()不会主动释放Lock。

notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程(这个一般用得少


——————————————————————————————————————————————————————————————————————————————————————
举例:
try:
    import threading
except ImportError:
    import dummy_threading

def worker(num,num2,key):
    print ("WORKER is :",num,num,key)

for i in range(5):
    t = threading.Thread(target = num, args = (i,i+1),kwargs = {"key":i+2,})
    t.start()

我们创建实例t ,将target 设为函数woker,而此时 *args,和**kwargs 都作为woker()的入口参数。
这个函数的结果为:
WORKER is : 0 0 2
WORKER is : 1 1 3
WORKER is : 2 2 4
WORKER is : 3 3 5
WORKER is : 4 4 6
——---------------------------------------------------
例2:

try:
    import threading
except ImportError:
    import dummy_threading

import time

def worker():
    print (threading.current_thread().getName(),"starting ")
    time.sleep(2)
    print (threading.current_thread().getName(),"ending")

def my_service():
    print (threading.current_thread().getName(),"starting")
    time.sleep(3)
    print (threading.current_thread().getName(),"ending")

t = threading.Thread(target = worker,name = "worker")
t1 = threading.Thread(target = my_service ,name = "my_service")
t2 = threading.Thread(target = worker)
t.start()
t1.start()
t2.start()
--输出:
worker starting
my_service starting
Thread-1 starting
worker ending
Thread-1 ending
my_service ending
      用 current_thread()返回当前运行的线程,用getName()方法获得线程的名字,我们可以通过通过setName()修改名字。如果当我们创建实例时没有设定线程的名字,那么相称的名字的格式为“Thread-N”,N为非零的整数。
------------------------------------------------------------
例3:
守护线程和非守护线程:
守护线程可以一直运行而不阻塞主程序推出。如果一个服务器无法用一种容易的方法来中断线程,或者希望线程工作到一半时终止而不损失或者破坏数据,对于这些服务使用守护线程就很有用。要设置一个守护线程可以用setDaemin(),并提供参数True。

要等待一个守护线程完成工作,需要使用join()方法。

————————————————————————————————

例四:threading.Lock


import time
import threading
import random
class Counter():
    def __init__(self,start = 0):
        self.lock = threading.Lock()
        self.value = start
    def increment(self):
        self.lock.acquire()
        try:
            self.value = self.value + 1
        finally:
            self.lock.release()
def worker(c):
    pause = random.random()
    print ("starting",threading.current_thread().getName())
    print("Sleeping :",pause)
    time.sleep(pause)
    c.increment()
    print("Ending")

c = Counter()

for i in range(5):
    t = threading.Thread(target = worker ,args = (c,))
    t.start()
mainThread = threading.current_thread()

for t in threading.enumerate():
    if t is not mainThread:
        t.join()

print ("counter",c.value)