python中的多线程(python中的多线程能提高速度吗)
python中的多线程(python中的多线程能提高速度吗)
线程和进程
进程是资源分配的最小单位。每个进程都拥有自己的地址空间、内存、数据栈以及其他用于追踪执行的辅助数据。操作系统管理其上所有进程的执行,并为这些进程合理地分配时间。进程也可以通过派生(fork或spawn)新的进程来执行其他任务,不过因为每个新进程也都拥有自己的内存和数据栈等,所以只能采用进程间通信(IPC)的方式共享信息 线程是程序执行的最小单位。线程与进程类似,不过它们是在同一个进程下执行的,并享有相同的上下文。线程包括开始、执行顺序和结束三部分。它有一个指令指针,用于记录当前运行的上下文。当其他线程运行时,它可以被抢占(中断)和临时挂起(也称为睡眠)——这种做法叫做让步(yielding) 一个进程中的各个线程与主线程共享同一片数据空间,因此相比于独立的进程而言,线程间的信息共享和通信更加容易。线程一般都是以并发方式执行,正是由于这种并行和数据共享进制,使得多任务间的协作称为了可能
全局解释器锁
Python代码的执行是由Python虚拟机进程控制的,对Python虚拟机的访问是由全局解释器锁(GIL)控制的。尽管Python解释器中可以运行多个线程,但是有个这个锁,在任意给定时刻只有一个线程会被解释器执行
退出线程
当一个线程完成函数的执行时,它就会退出。不建议使用thread模块的一个明显的原因是:在主线程退出之后,所有其他线程都会在没有清理的情况下直接退出,而另一个模块threading会确保在所有"重要的"子线程退出前,保证整个进程的存活
thread模块
thread模块除了派生线程外,还提供了基本的同步数据结构,称为锁对象。其主要的线程方法和锁对象方法有:
thread 模块的方法 | 描述 |
start_new_thread(function, args, kwargs=None) | 派生一个新的线程,使用给定的args和可选的kwargs来执行function |
allocate_lock() | 分配LockType锁对象 |
exit() | 给线程退出指令 |
LockType锁对象的方法 | 描述 |
acquire(wait=None) | 尝试获取锁对象 |
locked() | 如果获取了锁对象则返回True,否则返回False |
release() | 释放锁 |
在下面的例子中,为了实现线程的同步,要对每一个线程都加锁,执行完之后再释放锁,最后一个循环暂停主线程,直到所有锁都被释放后才可以继续执行
import _thread as threadfrom time import sleep, ctimeloops = [4, 2] #sleep时间def loop(nloop, nsec, lock): print("start loop", nloop, "at:", ctime()) sleep(nsec) print("loop", nloop, "done at:", ctime()) lock.release() #释放锁,每个线程执行完,都会释放自己的锁def main(): print("starting at:", ctime()) locks = [] #创建一个锁列表 nloops = range(len(loops)) #range(2) for i in nloops: lock = thread.allocate_lock() #获取锁对象 lock.acquire() #获得每个锁,效果相当于"把锁锁上" locks.append(lock) #将锁添加到锁列表中 for i in nloops: thread.start_new_thread(loop, (i, loops[i], locks[i])) for i in nloops: while locks[i].locked(): pass #等待(暂停主线程),直到所有锁被释放后才会继续执行 print("all DONE at:", ctime())if __name__ == "__main__": main()
threading模块
threading模块提供了更高级别、功能更全面的线程管理。threading模块的Thread类是主要的执行对象,它有thread模块中没有的很多函数
Thread对象数据属性 | 描述 |
name | 线程名 |
ident | 线程的标识符 |
daemon | 布尔标志,表示这个线程是否是守护线程 |
| Thread对象方法 | 描述 | | init(group=None, target=None, name=None, args=(), kwargs={}. verbose=None, daemon=None) | 实例化一个线程对象,需要有一个可调用的target,以及参数args或kwargs,还可以传递name或group参数,不过后者还未实现。此外,verbose标志也是可接受的,而daemon的值会设定thread.daemon属性/标志 | | start() | 开始执行该线程 | | run() | 定义线程功能的方法(通常在子类中被应用开发者重写) | | join(timeout=None) | 直至启动的线程终止之前一直挂起,除非给出了timeout(秒),否则会一直阻塞 |
使用Thread类,可以有很多方法来创建线程。这里说其中的两种方法:
创建Thread的实例,传给它一个函数派生Thread的子类,并创建子类的实例
创建Thread的实例
在下面的例子中,做了哪些修改呢?使用thread实现的锁没了,取而代之的是一组Thread对象。当实例化每个Thread对象时,把函数(target)和参数(args)传进去,然后得到返回的Thread实例。调用Thread()实例化Thread和调用thread.start_new_thread()的最大区别是新线程不会立即开始执行 当所有线程都分配完成之后,通过调用每个线程的start()方法让它们开始执行,相比于管理一组锁(分配、获取、释放、检查锁状态等)而言,这里只需要为每个线程调用join()方法即可。join()方法将等待线程结束,或者在提供了超时时间的情况下,达到超时时间。使用join()方法要比等待锁释放的无限循环更加清晰。如果主线程还有其他的事情要做,而不是等待这些线程完成,就可以不调用join()
import threadingfrom time import sleep, ctimeloops = [4, 2]def loop(nloop, nsec): print("start loop", nloop, "at:", ctime()) sleep(nsec) print("loop", nloop, "done at:", ctime())def main(): print("starting at:", ctime()) threads = [] nloops = range(len(loops)) for i in nloops: t = threading.Thread(target=loop, args=(i, loops[i])) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() print("all DONE at:", ctime())if __name__ == "__main__": main()
派送Thread的子类
派送出来的子类MyThread继承了父类Thread的构造方法,同时又新增了自己独有的实例属性
import threadingfrom time import sleep, ctimeloops = [4, 2]class MyThread(threading.Thread): def __init__(self, func, args, name=""): threading.Thread.__init__(self) self.name = name self.func = func self.args = args def run(self): self.func(*self.args)def loop(nloop, nsec): print("start loop", nloop, "at:", ctime()) sleep(nsec) print("loop", nloop, "done at:", ctime())def main(): print("starting at:", ctime()) threads = [] nloops = range(len(loops)) for i in nloops: t = MyThread(loop, (i, loops[i]), loop.__name__) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() print("all DONE at:", ctime()) if __name__ == "__main__": main()
还可以对MyThread类进程修改,增加一些调试信息的输出,并将其存储为一个名为myThread的独立模块,以便后面的模块引入调用。除了简单的调用函数外,还可以把结果保存在实例属性self.res,并创建一个新的方法getResult()来获取这个值
import threadingfrom time import ctimeclass MyThread(threading.Thread): def __init__(self, func, args, name=""): threading.Thread.__init__(self) self.name = name self.func = func self.args = args def getResult(self): return self.res def run(self): print("starting", self.name, "at:", ctime()) self.res = self.func(*self.args) print(self.name, "finished at:", ctime())
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~