什么是线程?你为什么需要它?Python是一种线性语言。但是当你需要更多的处理能力时,线程模块就派上用场了。Python中的线程不能用于并行CPU计算。但它非常适合I/O操作,例如网页抓取,因为处理器处于空闲状态,正在等待数据。线程改变了游戏规则,因为许多与网络/数据I/O相关的脚本大部分时间都在等待来自远程源的数据。有时下载可能没有链接(例如,如果您正在爬取不同的网站),处理器可以并行地从不同的数据源下载并在最后合并结果。线程包含在标准库中:importthreadingfromqueueimportQueueimporttime您可以使用target作为可调用对象,args将参数传递给函数,并开始启动线程:deftestThread(num):printnumif__name__=='__main__':foriinrange(5):t=threading.Thread(target=testThread,arg=(i,))t.start()lock(锁)你通常希望你的线程能够在线程之间使用或修改公共变量。为此,您必须使用一种叫做锁的东西。每当函数想要修改变量时,它都会锁定该变量。当另一个函数想要使用一个变量时,它必须等到变量被解锁。假设有两个函数都对一个变量进行了1次迭代。锁允许您确保一个函数可以访问变量、执行计算并在另一个函数访问同一变量之前写回该变量。您可以使用打印锁来确保一次只能打印一个线程。这可以防止文本在打印时变得杂乱无章(并导致数据损坏)。在下面的代码中,我们有10个要完成的作业和5个将要完成的工作:get())q.task_done()q=Queue()forxinrange(5):thread=threading.Thread(target=threader)#thisensuresthethreadwilldiewhenthemainthreaddies#cansett.daemontoFalseifyouwantittokeeprunningt.daemon=Truet.start()forjobinrange10):q.put(job)多线程并不总是完美的解决方案我们发现许多教程倾向于忽略使用他们刚刚教给您的工具的缺点。了解使用所有这些工具的优缺点非常重要。例如:管理线程需要时间,因此它适用于基本任务(如示例)线程增加了程序的复杂性,这使得调试更加困难什么是多处理?它与线程有何不同?在没有multiprocessing的情况下,由于GIL(GlobalInterpreterLock),Python程序很难最大化系统的规范。Python的设计并未考虑到个人计算机可能具有多个内核。所以GIL是必须的,因为Python不是线程安全的,访问Python对象时有全局强制锁。虽然不完美,但它是一种非常有效的内存管理机制。多处理允许您创建可以并发运行(绕过GIL)并使用整个CPU内核的程序。尽管它与线程库根本不同,但语法非常相似。多进程库为每个进程提供了自己的Python解释器和GIL。因此,与线程相关的常见问题,例如数据损坏和死锁,不再是问题。因为进程不共享内存,所以它们不能同时修改同一块内存。让我们开始代码演示:importmultiprocessingdefspawn():print('test!')if__name__=='__main__':foriinrange(5):p=multiprocessing.Process(target=spawn)p.start()如果你有共享数据库,您希望确保在启动新数据库之前等待相关进程完成。foriinrange(5):p=multiprocessing.Process(target=spawn)p.start()p.join()#thislineallowsyoutowaitforprocesses如果您希望将参数传递给进程,您可以使用args来实现:importmultiprocessingdefspawn(num):print(num)if__name__=='__main__':foriinrange(25):##rightherep=multiprocessing.Process(target=spawn,args=(i,))p.start()这是一个简单的例子,因为你注意到了是的,数字的顺序与您预期的顺序不同(没有p.join())。与线程一样,多进程也有缺点……你必须挑一个缺点:在进程之间移动数据会产生I/O开销整个内存被复制到每个子进程中,这对于更严肃的程序会带来很多开销我们应该使用哪个如果您的代码有大量I/O或网络使用:多线程是您的最佳选择,因为它的开销很低如果您有GUI:多线程是您的最佳选择,这样您的UI线程就不会被锁定代码受CPU限制:你应该使用多处理(如果你的机器有多个内核)
