• Python学习——Python线程


    一、线程创建

     1 #方法一:将要执行的方法作为参数传给Thread的构造方法
     2 import threading
     3 import time
     4 
     5 def show(arg):
     6     time.sleep(2)
     7     print('thread' + str(arg))
     8 
     9 for i in range(10):
    10     t = threading.Thread(target=show,args=(i,))
    11     time.sleep(2)
    12     t.start()
    13 
    14 #方法2:从Thread继承,并重写run()
    15 class MyThread(threading.Thread):
    16     def __init__(self,num):
    17         threading.Thread.__init__(self)
    18         self.num = num
    19 
    20     def run(self)):#定义每个线程要运行的函数
    21         print("running on number:%s" %self.num)
    22         time.sleep(3)
    23 
    24 
    25 if __name__ ==  '__main__':
    26     t1 = MyThread(1)
    27     t2 = MyThread(2)
    28     t1.start()
    29     time.sleep(3)
    30     t2.start()

    注解:
    Thread(group=None,target=None,name=None,args=(),kwargs={})
    group:线程组,目前还没有实现,库引用时提示必须是None
    target:要执行的方法
    name:线程名
    args/kwargs:要传入方法的参数,args和kwargs两个参数其实是二选一
    #实例方法
    isAlive():返回线程是否在运行
    get/setName(name):获取/设置线程名
    is/setDaemon(bool):获取/设置是否守护线程。初始值从创建该线程的线程继承,当没有非守护线程仍在运行时,程序将终止
    start():启动线程
    join([timeout]):阻塞当前上下文环境的线程。

    二、Python多线程用法

     1 import threading
     2 from time import ctime,sleep
     3 
     4 def music(func):
     5     for i in range(2):
     6         print("I was listening to %s. %s" %(func,ctime()))
     7         sleep(1)
     8 def move(func):
     9     for i in range(2):
    10         print("I was at the %s! %s" %(func,ctime()))
    11         sleep(5)
    12 
    13 threads = []
    14 t1 = threading.Thread(target=music,args=('童话镇',))
    15 threads.append(t1)
    16 t2 = threading.Thread(target=move,args=('变形金刚',))
    17 threads.append(t2)
    18 
    19 if __name__ == '__main__':
    20     for t in threads:
    21         t.setDaemon(True)
    22         t.start()
    23 
    24     print("all over %s" %ctime())

    注:

    threads = []

    t1 = threading.Thread(target=music,args=('童话镇',))

    threads.append(t1)

      创建了threads数组,创建线程t1,使用threading.Thread()方法,在这个方法中调用music方法target=music,args方法对music进行传参。 把创建好的线程t1装到threads数组中。

      接着以同样的方式创建线程t2,并把t2也装到threads数组。

    for t in threads:

      t.setDaemon(True)

      t.start()

    最后通过for循环遍历数组。(数组被装载了t1和t2两个线程)

    setDaemon()

      setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print "all over %s" %ctime()后,没有等待子线程,直接就退出了,同时子线程也一同结束。

           serDeamon(False)(默认)前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,主线程停止。

    运行结果:

    I was listening to 童话镇. Thu Jun 22 23:23:07 2017
    I was at the 变形金刚! Thu Jun 22 23:23:07 2017
    all over Thu Jun 22 23:23:07 2017
    

             从执行结果来看,子线程(muisc 、move )和主线程(print "all over %s" %ctime())都是同一时间启动,但由于主线程执行完结束,所以导致子线程也终止。 

    调整程序:

     

    1 if __name__ == '__main__':
    2     for t in threads:
    3         t.setDaemon(True)
    4         t.start()
    5     
    6     t.join()
    7 
    8     print "all over %s" %ctime()

             加了join()方法,用于等待线程终止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

             join()方法的位置是在for循环外的,也就是说必须等待for循环里的两个进程都结束后,才去执行主进程。

    运行结果:

    1 ############运行结果###################
    2 I was listening to 童话镇. Thu Jun 22 23:34:22 2017
    3 I was at the 变形金刚! Thu Jun 22 23:34:22 2017
    4 I was listening to 童话镇. Thu Jun 22 23:34:23 2017
    5 I was at the 变形金刚! Thu Jun 22 23:34:27 2017
    6 all over Thu Jun 22 23:34:32 2017

    从结果的时间可以看出每首歌之间等待1秒,电影之间等待5秒,但是是同步进行的,总的时间为5秒

    三、线程锁(LOCK,RLOCK)
             由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。

      Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。

      可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。  

      RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。

      可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

      简言之:Lock属于全局,Rlock属于线程。

    1,未使用锁

     1 import threading
     2 import time
     3 
     4 num = 0
     5 
     6 def show(arg):
     7     global num
     8     time.sleep(1)
     9     num +=1
    10     print(num)
    11 
    12 for i in range(10):
    13     t = threading.Thread(target=show, args=(i,))
    14     t.start()
    15 
    16 print('main thread stop')

    多次运行可能产生混乱。这种场景就是适合使用锁的场景。

    2.使用锁

     1 import threading
     2 import time
     3 
     4 num = 0
     5 lock = threading.RLock()
     6 
     7 # 调用acquire([timeout])时,线程将一直阻塞,
     8 # 直到获得锁定或者直到timeout秒后(timeout参数可选)。
     9 # 返回是否获得锁。
    10 def show(arg):
    11     lock.acquire()
    12     global num
    13     time.sleep(1)
    14     num +=1
    15     print(num)
    16     lock.release()
    17 
    18 for i in range(10):
    19     t = threading.Thread(target=show, args=(i,))
    20     t.start()
    21 
    22 print('main thread stop')

    加上锁后数字会一步步打印出来,不会因为拥堵而错乱的情况!


    四、信号量(Semaphore)

    互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

     1 import threading, time
     2 
     3 def run(n):
     4     semaphore.acquire()
     5     time.sleep(3)
     6     print("run the thread: %s" % n)
     7     semaphore.release()
     8 
     9 if __name__ == '__main__':
    10     num = 0
    11     semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行
    12     for i in range(20):
    13         t = threading.Thread(target=run, args=(i,))
    14         t.start()

     五、事件(event)

    Python线程的事件主要用于主线程控制其他线程的执行,事件主要提供了三个方法:set、wait、clear

    事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。

    clear:将“Flag”设置为False

    set:将“Flag”设置为True

    用threading.Event实现线程间的通讯

    threading.Event使一个线程等待其他线程的通知,把这个Event传递到线程对象中,Event默认内置了一个标志,初始值为False。
    一旦该线程通过wait()方法进入等待状态,直到另一个线程调用该Event的set()方法将内置标志设置为True时,
    该Event会通知所有等待状态的线程恢复运行。

     1 import threading
     2 
     3 def do(event):
     4     print('start')
     5     event.wait()
     6     print('end')
     7 
     8 event_obj = threading.Event()
     9 
    10 for i in range(10):
    11     t = threading.Thread(target=do, args=(event_obj,))
    12     t.start()
    13 
    14 event_obj.clear() #继续阻塞
    15 
    16 inp = input('input:')
    17 if inp == 'true':
    18     event_obj.set()  # 唤醒

    六、条件(condition)
    所谓条件变量,即这种机制是在满足特定条件之后,线程才可以访问相关的数据!

    它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法

    一个简单的生产消费者模型,通过条件变量的控制产品数量的增减,调用一次生产者产品就是+1,调用一次消费者产品就会-1.
    使用 Condition 类来完成,由于它也可以像锁机制那样用,所以它也有 acquire 方法和 release 方法,而且它还有
    wait, notify, notifyAll 方法。
     1 import threading
     2 import  time
     3 
     4 # 产品类
     5 class Goods:
     6     def __init__(self):
     7         self.count = 0
     8 
     9     def add(self, num=1):
    10         self.count += num
    11 
    12     def sub(self):
    13         if self.count >= 0:
    14             self.count -= 1
    15 
    16     def empty(self):
    17         return self.count <= 0
    18 
    19 # 生产者
    20 class Producer(threading.Thread):
    21     def __init__(self, condition, goods, sleeptime=1):
    22         threading.Thread.__init__(self)
    23         self.cond = condition
    24         self.goods = goods
    25         self.sleeptime = sleeptime
    26 
    27     def run(self):
    28         cond = self.cond
    29         goods = self.goods
    30         while True:
    31             # 锁住资源
    32             cond.acquire()
    33             goods.add()
    34             print("产品数量:", goods.count, "生产者线程")
    35             # 唤醒所有等待的线程 -> 其实就是唤醒消费者进程
    36             cond.notifyAll()
    37             # 解锁资源
    38             cond.release()
    39             time.sleep(self.sleeptime)
    40 
    41 
    42 # 消费者
    43 class Consumer(threading.Thread):
    44     def __init__(self, condition, goods, sleeptime=2):
    45         threading.Thread.__init__(self)
    46         self.cond = condition
    47         self.goods = goods
    48         self.sleeptime = sleeptime
    49 
    50     def run(self):
    51         cond = self.cond
    52         goods = self.goods
    53 
    54         while True:
    55             time.sleep(self.sleeptime)
    56             # 锁住资源
    57             cond.acquire()
    58             # 如无产品则让线程等待
    59             while goods.empty():
    60                 cond.wait()
    61             goods.sub()
    62             print("产品数量:", goods.count, "消费者线程")
    63             
    64 
    65 g = Goods()
    66 c = threading.Condition()
    67 pro = Producer(c, g)
    68 pro.start()
    69 con = Consumer(c, g)
    70 con.start()

    七、定时器(Timer)

     1 import threading
     2 def SayHello():
     3     print("hello world!")
     4     t=threading.Timer(3,SayHello)
     5     t.start()
     6 def other_func():
     7     print("let me running!")
     8     t=threading.Timer(1,other_func)
     9     t.start()
    10 
    11 if __name__ == "__main__":
    12     SayHello()
    13     other_func()

     

     

     

     

  • 相关阅读:
    数据库DQL(Data Query Language)语言学习之三:排序查询
    数据库DQL(Data Query Language)语言学习之二:条件查询
    MySQL中的通配符
    SQL查询文档网站
    python之特殊方法
    java之静态函数和静态变量
    java之类和对象
    python之类的继承
    python的面向对象编程
    python之模块(在命令行当中使用pip install 模块来进行模块的安装)
  • 原文地址:https://www.cnblogs.com/huan-ge/p/7067931.html
Copyright © 2020-2023  润新知