zoukankan      html  css  js  c++  java
  • 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()

     

     

     

     

  • 相关阅读:
    组装query,query汇总,query字段
    POJ 1276, Cash Machine
    POJ 1129, Channel Allocation
    POJ 2531, Network Saboteur
    POJ 1837, Balance
    POJ 3278, Catch That Cow
    POJ 2676, Sudoku
    POJ 3126, Prime Path
    POJ 3414, Pots
    POJ 1426, Find The Multiple
  • 原文地址:https://www.cnblogs.com/huan-ge/p/7067931.html
Copyright © 2011-2022 走看看