python 多线程
python 多线程
python threading模块提供线程相关操作。
线程是应用程序工作的最小单元。
1、线程是什么机理工作的?
一个py程序可以看做一个主线程, 主线程里可以创建多个子线程。
py程序从上到下执行完毕后,主线程即执行完毕。
中间主线程如需等待子线程的返回值会等子线程,否则各自执行。另一种情况是子线程中有等待,那么主线程也不会等子线程。
机理:通俗的讲计算机中只有一根大的指针(可能会和存储用的分开),这根指针是在内存中用到,调拨程序指令(可以理解为寻址)。
比如同时开了是个子进程,并且是同一个对象开的(即要求同时并行),指针是忙碌在各个子进程之间,先将A1子进程中的a1指令执行后,调到A2子进程的a2指令。所以会看到这样的例子,注意时间戳有细小不同。
#!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time def show(arg): time.sleep(1) print 'thread'+str(arg) print time.ctime() print time.time() for i in range(10): t = threading.Thread(target=show, args=(id(i),)) t.start() print 'main thread stop' >>> main thread stop >>> thread8301716thread8301764thread8301728thread8301740thread8301776thread8301704thread8301788thread8301752thread8301692thread8301680 Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016Thu Dec 01 08:27:40 2016 1480552060.61480552060.611480552060.621480552060.631480552060.641480552060.641480552060.651480552060.661480552060.671480552060.67
再举一个例子,如果子进程准备就绪,而主进程还在跑,现在是各自执行吗?还是等待主进程执行后才会开始子进程。
#!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time def show(arg): time.sleep(2) print 'thread'+str(arg) print time.ctime() print time.time() for i in range(10): t = threading.Thread(target=show, args=(id(i),)) t.start() print "main thread sleep" slep = 5 for i in range(slep): time.sleep(1) print "has slp %ss"%i a=5 a=a+100 print a print 'main thread stop' >>> main thread sleep has slp 0s thread9481436thread9481412thread9481424thread9481388thread9481376thread9481364thread9481328thread9481340thread9481352thread9481400 Thu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016has slp 1sThu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016Thu Dec 01 09:19:44 2016 1480555184.311480555184.311480555184.321480555184.331480555184.331480555184.341480555184.351480555184.361480555184.361480555184.37 has slp 2s has slp 3s has slp 4s 105 main thread stop >>>
谁都不会等谁,按照时间进行。
还有这样的例子,验证到底在子进程真的是指针在来回跳动吗?
import threading import time def show(arg): time.sleep(2) print '2-----thread'+str(arg) time.sleep(2) print "3----",time.ctime() time.sleep(2) print "4--------",time.time() def deng(arg): time.sleep(2) arg = arg*1000000 time.sleep(2) print "3------%s"%arg time.sleep(2) print "4-----+++++++++" def qwe(arg): time.sleep(2) print "2-------qwe" time.sleep(2) print "qweqwe" time.sleep(2) print "4-----zzzzzzzzzzzzzzzzzz" a = [show,deng,qwe] for i in range(3): t = threading.Thread(target=a[i], args=(id(i),)) t.start() '''print "main thread sleep" slep = 5 for i in range(slep): time.sleep(1) print "has slp %ss"%i a=5 a=a+100 print a''' print 'main thread stop' >>> main thread stop >>> 2-----thread90882202-------qwe 3------9088208000000 3----qweqwe Thu Dec 01 10:13:14 2016 4-----+++++++++ 4-----zzzzzzzzzzzzzzzzzz4-------- 1480558396.93
可以看到几个函数中的第二部都在(基本同一时刻)执行(指针在几个函数中转换),然后都在sleep,如果有一个sleep时间过长,其余两个线程会继续执行不会等待。这就证明指针不会在一个线程中一直执行,而是会一执行在各个子线程中执行程序。
join的理解:在当前线程让指针加入一个在本线程内的操作时间,比如join(2),就是在这个线程中再多执行两秒后才能跳转到另外线程中。
可以算作主线程将指针放置在子线程中等待,所有等待时间都是计算在主线程之内。
这里介绍一个编程技巧,适用场景为多部设备一起执行任务时可以让子线程的任务都执行完,然后执行主线程的任务。
多线程任务技巧
http://www.cnblogs.com/lx63blog/articles/6248943.html
2、线程锁的作用
不加锁的效果
#! /usr/bin/env python import threading import time gl = 1 def f1(): global gl gl = gl+1 print "f1 out ",gl def f2(): global gl gl = gl+1 print "f2 out ",gl tl =[f1,f2] for i in tl: t = threading.Thread(target=i) t.start() time.sleep(3) print "main end" ========================= RESTART: C:/Python27/rl.py ========================= f1 out f2 out 33 main end >>>
产生了脏数据。
加了线程锁的效果
#! /usr/bin/env python import threading import time #from weapon.ap import FuncTimer lock = threading.RLock() gl = 1 def f1(): lock.acquire() global gl gl = gl+1 print "f1 out ",gl lock.release() def f2(): lock.acquire() global gl gl = gl+1 print "f2 out ",gl lock.release() #ft = FuncTimer() #@ft.functimer def prp(): tl =[f1,f2] for i in tl: t = threading.Thread(target=i) t.start() time.sleep(3) print "main end" prp() >>> ========================= RESTART: C:/Python27/rl.py ========================= f1 out 2 f2 out 3 main end cust time 3 >>>
3、生产者消费者模型
import queue
模型:管状存取模型
意义:1、为IO操作用户排队
2、在服务器性能允许的情况下,可以节省时间,因为在cpu调度指针未到queue时,线程可以一直加入直到queue上限。当指针调度到queue时可以一次全部执行,而这个操作对用户是感知不到时间变慢。