20170529——线程

来源:互联网 发布:海岛奇兵机枪升级数据 编辑:程序博客网 时间:2024/06/10 12:56

    • 线程
      • 1线程的简单调用
        • _thread
        • _thread线程调用函数需要加入数组tuple
        • threading
      • 2线程的复杂调用
        • 子类继承threading
      • 3线程的互斥锁如何修改共享资源
      • 4锁的总结
        • 锁的好处
        • 锁的坏处
      • 5线程死锁
      • 6线程Rlockacquire是依附于threadingLock或threadingRLock存在
      • 67线程的condition锁重要
      • 7threading线程共享queue
      • 8threading线程的evnet通讯
      • 1threading线程的evnet通讯2深入并通俗易懂
        • 2Event对象方法
      • 9线程join阻塞主进程和setDaemon守护线程
      • 10TreadLocal
        • ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接HTTP请求用户身份信息等这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源
        • 小结
        • 一个ThreadLocal变量虽然是全局变量但每个线程都只能读写自己线程的独立副本互不干扰ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题
      • 11线程常见的函数
        • 1semapore线程同时运行最大并发量
        • 2timer多少秒后线程执行任务
        • 3TSL为每个线程提供独立空间

线程

1、线程的简单调用:

_thread:

_thread线程调用函数需要加入数组tuple()

#coding=utf-8import threadfrom time import sleep,ctimedef sing():for i in range(3):    print "正在唱歌...%d"%i    sleep(1)def dance():    for i in range(3):        print "正在跳舞...%d"%i        sleep(1)if __name__ == '__main__':    print '---开始---:', ctime()     # 第一个参数:创建的新线程要执行的代码    # 第二个参数给新线程执行sing函数时传递的参数,即使没有参数也要传递空元组    thread.start_new_thread(sing, ())     thread.start_new_thread(dance, ())    sleep(5)    print '---结束---:', ctime()

threading:

#coding=utf-8import threadingimport timedef saySorry():    print "亲爱的,我错了,我能吃饭了吗?"    time.sleep(1)if __name__ == "__main__":    for i in range(5):        #threading线程调用函数,输入函数名saySorry即可,不要加(),也不不需要加入数组格式        t = threading.Thread(target=saySorry)        t.start()

2、线程的复杂调用:

子类继承threading:

#coding=utf-8import threadingimport timeclass MyThread(threading.Thread):    #如果线程接收参数,在__init__(self,*number)接收即可,*可以为任意个,包括0,number类型为tuple    def run(self):        for i in range(3):            time.sleep(1)            msg = "I'm "+self.name+' @ '+str(i)            print msgdef test():    for i in range(5):        t = MyThread()        t.start()if __name__ == '__main__':    test()

3、线程的互斥锁(如何修改共享资源):

#创建锁mutex = threading.Lock()#锁定mutex.acquire([timeout])  #[timeout]不写,默认为1,在1秒之内完成工作自动释放,0会出现难于预计的后果#释放mutex.release()

4、锁的总结:

  • 当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”

  • 直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

锁的好处:

  • 确保了某段关键代码只能由一个线程从头到尾完整地执行

锁的坏处:

  • 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了.
  • 由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁

5、线程死锁:

import threadingimport timeboymutex=threading.Lock()girlmutext=threading.Lock()class boy(threading.Thread):    def run(self):        if boymutex.acquire(1):#没有参数,一直等待acquire成功返回True            print(self.name+"boy i  am sorry  up")            time.sleep(1)            if girlmutext.acquire(1):                print(self.name + "boy i  am sorry  down")                girlmutext.release()            boymutex.release()class girl(threading.Thread):    def run(self):        if girlmutext.acquire(1): # 没有参数,一直等待,            print(self.name + "girl i  am sorry   up")            time.sleep(2)            #27-到这里解锁            if boymutex.acquire(1):                print(self.name + "girl i  am sorry  down")                boymutex.release()            girlmutext.release()boy1=boy()boy1.start()girl1=girl()girl1.start()

6、线程Rlock:acquire是依附于threading.Lock或threading.RLock存在

import threadingimport timeclass MyThread(threading.Thread):    def run(self):        global num        time.sleep(1)        if mutex.acquire(1):            num = num+1            msg = self.name+' set num to '+str(num)            print (msg)            mutex.acquire()     #第二次锁            mutex.release()     #第二次锁的解锁            mutex.release()num = 0mutex = threading.RLock()def test():    for i in range(5):        t = MyThread()        t.start()if __name__ == '__main__':    test()

6&7、线程的condition锁(重要):

# -*- coding: utf-8 -*-import threading, timeclass Seeker(threading.Thread):    def __init__(self, cond, name):        super(Seeker, self).__init__()        self.cond = cond        self.name = name    def run(self):        self.cond.acquire()        print (self.name + ': 我已经把眼睛蒙上了')        """        notify源码解析:            __waiters = self.__waiters            waiters = __waiters[:n] # 获取等待队列中的n个等待锁            for waiter in waiters:            waiter.release() # 释放Hider的等待锁            try:                __waiters.remove(waiter)            except ValueError:                pass        """        # 释放n个waiter锁,waiter线程准备执行        self.cond.notify()        print('notifyed...')        # 释放condition条件锁,waiter线程Hider真正开始执行        self.cond.wait()        print('waited...')        print (self.name + ': 我找到你了 ~_~')        self.cond.notify()        self.cond.release()        print (self.name + ': 我赢了')class Hider(threading.Thread):    def __init__(self, cond, name):        super(Hider, self).__init__()        self.cond = cond        self.name = name    def run(self):        self.cond.acquire()        """        wait()源码解析:            waiter = _allocate_lock() # 创建一把等待锁,加入waiters队列,等待notify唤醒            waiter.acquire() # 获取锁            self.__waiters.append(waiter)            saved_state = self._release_save() # 释放condition.lock全局条件锁,以便其他等待线程执行            if timeout is None:                waiter.acquire() # 再次获取锁,因为已经锁定无法继续,等待notify执行release        """        # wait()释放对琐的占用,同时线程挂起在这里,直到被notify并重新占有琐。        self.cond.wait()        print (self.name + ': 我已经藏好了,你快来找我吧')        self.cond.notify()        self.cond.wait()        self.cond.release()        print (self.name + ': 被你找到了,哎~~~')cond = threading.Condition()hider = Hider(cond, 'hider')seeker = Seeker(cond, 'seeker')hider.start()seeker.start()hider.join()seeker.join()print('end...')

7、threading线程共享queue:

# -*- coding:utf-8 -*-import threadingimport queueimport timeimport randommyqueue=queue.Queue(10)class butThread(threading.Thread):    def __init__(self,index,myqueue):        threading.Thread.__init__(self)        self.index=index        self.myqueue=myqueue    def run(self):        while True:            time.sleep(1)            item=self.myqueue.get()            if item is None:                break            print("客户",self.index,"物品",item,"买到")        self.myqueue.task_done()class creatorThread(threading.Thread):    def __init__(self,index,myqueue):        threading.Thread.__init__(self)        self.index=index        self.myqueue=myqueue    def run(self):        while True:            time.sleep(3)            num=random.randint(1,1000000)            self.myqueue.put("生产者"+str(self.index)+"肉夹馍"+str(num))            print("input 生产者"+str(self.index)+"肉夹馍"+str(num))        self.myqueue.task_done()for i in range(3):            #无限循环,对象生产和获取    creatorThread(i,myqueue).start()for i in range(8):    butThread(i,myqueue).start()# for i in range(10):           #简单生产,对象无限获取#     myqueue.put("肉夹馍"+str(i))## for i in range(8):#     butThread(i,myqueue).start()# for  i in range(3):           #无限循环,对象一次性生产,简单一次性获取#     creatorThread(i,myqueue).start()# while True:#     time.sleep(10)#     print("----------")#     while not myqueue.empty():#         print(myqueue.get())#     print("-----------")

8、threading线程的evnet通讯

import threadingimport timedef  goevent():    e=threading.Event() #事件对象    def go(): #函数内部的函数,嵌套        for i  in range(10):        #i为每一个等待的资源            e.wait() #等待            e.clear()#清理            print(i)    threading.Thread(target=go).start()#创建一个线程,go    return eev=   goevent()for  i  in  range(10):      #等待多少秒    time.sleep(i)    ev.set()
输出:0123456789

8.1、threading线程的evnet通讯2(深入并通俗易懂)

Event对象用于线程间的相互通信,实际上Condition对象在一定程度上已经实现线程间的通信,但Condition对象是每次仅有一个线程对共享数据进行操作,其他线程则等待。而Event对象是由线程设置的信号标志,如果信号标志为真,则其他线程等待直到信号解除。

8.2、Event对象方法:

  • set():设置Event对象内部的信号为真,

  • isSet():判断内部信号标志的状态,当Event对象使用set()方法后,isSet()方法返回真

  • clear():清除内部信号标志,当使用clear()方法后,isSet()方法就会返回假

  • wait():当内部信号为真的时才会执行,如果内部信号为假则会一直等待

#-*- coding:utf-8 -*-import threading            # 导入threading模块class mythread(threading.Thread):    def __init__(self,threadname):        threading.Thread.__init__(self,name = threadname)    def run(self):        global event        # 使用全局Event对象        if event.isSet():   # 判断Event对象内部信号标志            # print(event.isSet())            event.clear()   # 若已设置标志则清除,把event的值设为Flase,这样wait遇到False才会等待,如果wait遇到True永远不会停            # print(event.isSet())            event.wait()    # 调用wait方法            # print(event.isSet())            print (self.getName())        else:            # print (self.getName())            event.set() # 设置Event对象内部信号标志            print (self.getName())event = threading.Event()       # 生成Event对象event.set()             # 设置Event对象内部信号标志,第一次就把event设置为Truetl = []for i in range(10):    t = mythread(str(i))    tl.append(t)            # 生成线程列表for i in tl:    i.start()           # 运行线程
运行结果:      1           #event  event.set  可以分别理解为一个房间和一个房间的开关032547698

9、线程:join阻塞主进程和setDaemon守护线程

import threadingimport randomimport timeclass MyThread(threading.Thread):    def run(self):        wait_time=random.randrange(1,10)        print ("%s will wait %d seconds" % (self.name, wait_time))        time.sleep(wait_time)        print ("%s finished!" % self.name)if __name__=="__main__":    print ('main thread is waitting for exit...')for i in range(5):    t = MyThread()    #setDaemon(True)把子进程设为守护线程(非主要),主进程可以自由执行    t.setDaemon(True)     #join默认不设值,阻塞主进程,必须等待全部子进程执行完。    #t.join()        #join(1)设置为1的话,只会等待时间较短的子进程,再执行主进程,最后执行剩余的长时间sleep的子进程    t.start()print ('main thread finished!')
###########运行结果###########main thread is waitting for exit...Thread-1 will wait 4 secondsThread-2 will wait 3 secondsThread-3 will wait 5 secondsThread-4 will wait 5 secondsThread-5 will wait 6 secondsmain thread finished!

10、TreadLocal

#-*- coding:utf-8 -*-import threading# 创建全局ThreadLocal对象:local_school = threading.local()def process_student():    # 获取当前线程关联的student:    std = local_school.student    print('Hello, %s (in %s)' % (std, threading.current_thread().name))def process_thread(name):    # 绑定ThreadLocal的student:    local_school.student = name    process_student()#target目标函数;args需要传的值,类型是tuple;name设置线程的名字t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')t1.start()t2.start()t1.join()t2.join()
##运行结果Hello, Alice (in Thread-A)Hello, Bob (in Thread-B)

ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。

小结

一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题


11、线程常见的函数:

11.1、semapore:线程同时运行最大并发量

import threadingimport timesem=threading.Semaphore(3) #控制线程的数量,最大并发,没有并发等待def gothread():    #with是acquire和release的合并    with sem: #使用并发量控制        for i in range(10):            time.sleep(0.1)            print(threading.current_thread().name,i)for i in range(4):    threading.Thread(target=gothread).start()

11.2、timer:多少秒后线程执行任务

import timeimport osimport threading'''#主线程卡顿,主线不能干其他活while True:    os.system("notepad")    time.sleep(5)'''#定时线程def  go():    os.system("notepad")timeth=threading.Timer(5,go)timeth.start()#5,5秒循环,go执行,新的线程# timeth.cancel()#结束while True:    print("OK")    time.sleep(1)

11.3、TSL:为每个线程提供独立空间

import threadingimport timedata=threading.local() #class '_thread._local,线程独立存储空间#每一个线程独立存储,x不重合#print(type(data))t1=lambda x:x+1  #1+1=2t2=lambda x:x+"1"  #“1”+“1”=“11”def  printdata(func,x):#func接收t1,t2产生不同的行为    data.x=x #data是一个类,动态绑定,每一个线程的x都是独立的    print(id(data.x),threading.Thread.name)    for  i in range(5):        data.x=func(data.x)        print(threading.current_thread().name,data.x)        time.sleep(0.2)threading.Thread(target=printdata,args=(t1,1)).start()threading.Thread(target=printdata,args=(t2,"1")).start()
##运行结果1418634336 <property object at 0x00000000028F99A8>Thread-1 236809952 <property object at 0x00000000028F99A8>Thread-2 11Thread-1 3Thread-2 111Thread-1 4Thread-2 1111Thread-1 5Thread-2 11111Thread-1 6Thread-2 111111
原创粉丝点击