线程
1、启动一个线程
import threading import time def run(name): time.sleep(2) print('{name} is running the threading!!'.format(name = name)) if __name__ == '__main__': t = threading.Thread(target=run,args=('Chen',)) t.start() print('The main process is running!')
结果如下:
The main process is running!
Chen is running the threading!!
注:由此看出,线程启动后已与程序本身的线程(主线程)已经没有关系了,并不会等待主线程运行完毕后再运行手动启动的线程。
2、join()函数的意思是等调用该函数的实例线程运行完毕之后在运行主线程,例如在上边代码的基础上,在t.start()后边增加t.join(),则运行结果如下:
Chen is running the threading!!
The main process is running!
如果手动启动多个线程,要等所有的线程运行完毕后在运行主线程,则需要循环,如下:
import threading import time def run(name): time.sleep(4) print('{name} is running the threading!!'.format(name = name)) def run1(name): time.sleep(2) print('{name} is running the threading!!'.format(name = name)) time.sleep(1) if __name__ == '__main__': t1 = threading.Thread(target=run,args=('Chen',)) t2 = threading.Thread(target=run1, args=('Chen2',)) t1.start() t2.start() t2.join() print('The main process is running!')
结果如下:
Chen2 is running the threading!!
The main process is running!
Chen is running the threading!!
模型如下:
3、如果要等所有的程序运行完毕之后在运行主程序,则需要遍历所有手动启动的线程
import threading import time def run1(name): time.sleep(4) print('{name} is running the threading!!'.format(name = name)) def run2(name): time.sleep(2) print('{name} is running the threading!!'.format(name = name)) time.sleep(1) def run3(name): time.sleep(2) print('{name} is running the threading!!'.format(name = name)) t_list = [] if __name__ == '__main__': t1 = threading.Thread(target=run1,args=('Chen1',)) t2 = threading.Thread(target=run2,args=('Chen2',)) t3 = threading.Thread(target=run3,args=('Chen3',)) t1.start() t2.start() t3.start() t_list.append(t1) t_list.append(t2) t_list.append(t3) for t in t_list: t.join() print('The main process is running!')
这样主程序就会等所有的手动线程启动完成之后才会运行!
4、daemon thread 守护线程,守护线程就是伴随着其他线程的消亡而自动消亡的,他的执行情况不重要
import threading import time def run(name): time.sleep(1) print('I am the child of daemon threading {name}'.format(name = name)) def main(): print('The main threading is running!!') r = threading.Thread(target=run,args=('main',)) r.start() time.sleep(2) //这的时间大于run的时间,所以在main执行完后,run也执行完比,但当这的时间小于run()的时间,那么run()就没有执行完毕,即程序运行的结果为:The main threading is running和
//The threading has runned,就没有I am the child of daemon threading main了 if __name__ == '__main__': m = threading.Thread(target=main) m.setDaemon(True) //设置main为守护线程,当主线程执行完毕后,不管守护线程是否执行完毕,守护线程及子线程全部结束 m.start() //守护线程的设置一定要在线程开始之前设置(很正常的逻辑,小细节) m.join(timeout = 8) //这里的8sec表示最多不超过8s,当在小于8s的时间内守护线程运行完毕,主线程的运行时间可以小于8 print('The threading has runed
总结:守护线程是伴随其守护的线程而存亡的,当守护的线程结束时,守护线程及其子线程一并结束。
5.1、线程锁(互斥锁Mutex)
在同一个进程中,线程是共享空间的,当在同一个进程中启动多个线程时,而多个线程调用同一份数据时,此时就有可能出乱子了。例如:
import threading import time def run(): global num time.sleep(1) lock.acquire() num -= 1 lock.release() print('The result of num is:',num) lock = threading.Lock() num = 1000 t_list = [] if __name__ == '__main__': for i in range(1000): t = threading.Thread(target=run,args=()) t.start() t_list.append(t) for t in t_list: t.join()
加锁的主要目的在于每一次只能有一个线程对数据进行修改,而不至于出现第一个线程还没运行结束,第二个线程就过来取数据,这样两个线程运行的结果是一样的。运算模型如下
5.2递归锁 就时在父线程中加锁,然后在子线程中也加锁
启动多个线程,每个线程调用同样的两个方法A和B,两种方法分别处理同一块数据,就有可能出现互斥锁的情况,故需要再增加一层锁,就称谓递归锁!!
5.3 信号量(semaphore):就是同时允许多少个线程对同一块数据进行处理。使用方法如下:
import threading, time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s\n" % n) semaphore.release() num = 0 semaphore = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行 if __name__ == '__main__': for i in range(20): t = threading.Thread(target=run, args=(i,)) t.start()
5.4Timer
import threading def hello(): print("hello, world") t = threading.Timer(10,hello) t.start() # after 30 seconds, "hello, world" will be printed
6、Event()事件,就好比两个人再对话一样,是一个时间,事件里边包括两个人。
import threading import time event = threading.Event() def talk_1(name): count = 1 event.set() #设置的是讲话 while True: if count <= 5: print('{name} is talking!!'.format(name = name)) elif count > 5 and count <= 10: event.clear() print('我不讲了,我要看着你讲!!') else: count = 0 event.set() count += 1 time.sleep(1) def talk_2(name): while True: if not event.isSet(): print('{name} begin to talk!!'.format(name = name)) else: event.wait() print('{name} is looking at Lilei!!'.format(name = 'Lucy')) time.sleep(1) if __name__ == '__main__': t = threading.Thread(target=talk_1,args=('Lilei',)) t.start() c = threading.Thread(target=talk_2,args=('Lucy',)) c.start()
事件设置的是Lilei在讲话,Lucy在看着leilei讲话,讲完后,切换。event.wait()只有在事件被设置后才运行。
7、queue
queue有几种类型,先进先出,first in first out, 后进先出, last in first out, 还有一个优先权
import queue
q = queue.Queue()生成一个先进先出的queue
q = queue.Lifoqueue()生成一个后进先出的queue
q = queue.PriorityQueue(maxsize = internal)优先队列再生成实例是要求确定队列的大小,即需要确定maxsize的数值,压栈是需要确定队列的先后顺序例如:
q.put((1,20))
q.put((2,30))
q.put((0,50))把队列中第一个位置放50,第二个位置放20,第三个位置放30.
消费者买包子模型,就是生产者不停的往蒸笼里放包子,做好的包子不断的被消费者购买,蒸笼的大小是不变的,这也是queue区别与list的重要的一个点!!