Python多线程总结
多线程常用模板
在实际处理数据时,因系统内存有限,我们不可能一次把所有数据都导出进行操作,所以需要批量导出依次操作。为了加快运行,我们会采用多线程的方法进行数据处理, 以下为我总结的多线程批量处理数据的模板: import threading # 从数据库提取数据的类 class Scheduler(): def __init__(self): self._lock = threading.RLock() self.start = 0 # 每次取10000条数据 self.step = 10000 def getdata(self): # 上锁,以免多线程同时对数据库进行访问,取出重复数据 self._lock.acquire() # 进行取数据操作 data = "select * from table" "where id between self.start and self.start + self.step" # 取完数据后,指针后移 self.start += self.step self._lock.release() return data # 处理数据的过程写在这里 def processdata(): # 从该实例中提取数据 data = scheduler.getdata() while data: # 进行处理数据的具体操作: # 去重、补缺、运算...只要还有数据,本线程就继续取新数据 # 然后再获取数据,进行循环 data = scheduler.getdata() # 创建多线程,threads_num为创建的线程数 def threads_scheduler(threads_num): threads = [] for i in range(threads_num): # 创建线程 td = threading.Thread(target=processdata, name="th"+str(i+1)) threads.append(td) for t in threads: # 启动线程 t.start() for t in threads: # 子线程守护 t.join() print("数据已全部处理成功") if __name__=="__main__": # 实例化一个调度器,初始化参数 scheduler = Scheduler() # 创建线程,开始处理数据 threads_scheduler(4)
主要分为三大部分: Scheduler 类,负责初始化参数,getdata 方法负责提取数据processdata 方法中写具体处理数据的流程threads_scheduler 方法负责创建线程
多线程重点回顾
共分4部分对多线程的内容进行总结。 多线程threading
先为大家介绍线程的相关概念: 主线程:当一个程序启动时,就有一个进程被操作系统 OS 创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程Main Thread 。因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程。子线程:使用 threading 、ThreadPoolExecutor 创建的线性均为子线程。主线程的重要性体现在两方面: 是产生其他子线程的线程 通常它必须最后完成执行,比如执行各种关闭动作
在飞车程序中,如果没有多线程,我们就不能一边听歌一边玩飞车,听歌与玩游戏不能并行;在使用多线程后,我们就可以在玩游戏的同时听背景音乐。在这个例子中启动飞车程序就是一个进程,玩游戏和听音乐是两个线程。
Python 提供了threading 模块来实现多线程: threading.Thread 可以创建线程setDaemon(True) 为守护主线程,默认为False ;join() 为守护子线程。from time import sleep import threading def music(music_name): for i in range(2): print("正在听{}".format(music_name)) sleep(1) print("music over") def game(game_name): for i in range(2): print("正在玩{}".format(game_name)) sleep(3) print("game over") threads = [] t1 = threading.Thread(target=music,args=("稻香",)) threads.append(t1) t2 = threading.Thread(target=game,args=("飞车",)) threads.append(t2) if __name__ == "__main__": for t in threads: # t.setDaemon(True) t.start() for t in threads: t.join() print("主线程运行结束")线程池
因为新建线程系统需要分配资源、终止线程系统需要回收资源,所以如果可以重用线程,则可以减去新建/终止的开销以提升性能。同时,使用线程池的语法比自己新建线程执行线程更加简洁。
Python 为我们提供了ThreadPoolExecutor 来实现线程池,此线程池默认子线程守护。它的适应场景为突发性大量请求或需要大量线程完成任务,但实际任务处理时间较短。 from time import sleep # fun为定义的待运行函数 with ThreadPoolExecutor(max_workers=5) as executor: ans = executor.map(fun, [遍历值]) for res in ans: print(res) with ThreadPoolExecutor(max_workers=5) as executor: list = [遍历值] ans = [executor.submit(fun, i) for i in list] for res in as_completed(ans): print(res.result())
其中 max_workers 为线程池中的线程个数,常用的遍历方法有map 和submit+as_completed 。根据业务场景的不同,若我们需要输出结果按遍历顺序返回,我们就用map 方法,若想谁先完成就返回谁,我们就用submit+as_complete 方法。 线程互斥
我们把一个时间段内只允许一个线程使用的资源称为临界资源,对临界资源的访问,必须互斥的进行。互斥,也称间接制约关系。线程互斥指当一个线程访问某临界资源时,另一个想要访问该临界资源的线程必须等待。当前访问临界资源的线程访问结束,释放该资源之后,另一个线程才能去访问临界资源。锁的功能就是实现线程互斥。
我把线程互斥比作厕所包间上大号的过程,因为包间里只有一个坑,所以只允许一个人进行大号。当第一个人要上厕所时,会将门上上锁,这时如果第二个人也想大号,那就必须等第一个人上完,将锁解开后才能进行,在这期间第二个人就只能在门外等着。这个过程与代码中使用锁的原理如出一辙,这里的坑就是临界资源。 Python 的threading 模块引入了锁。threading 模块提供了Lock 类,它有如下方法加锁和释放锁: acquire() :对 Lock 加锁,其中timeout 参数指定加锁多少秒release() :释放锁class Account: def __init__(self, card_id, balance): # 封装账户ID、账户余额的两个变量 self.card_id= card_id self.balance = balance def withdraw(account, money): # 进行加锁 lock.acquire() # 账户余额大于取钱数目 if account.balance >= money: # 吐出钞票 print(threading.current_thread().name + "取钱成功!吐出钞票:" + str(money),end=" ") # 修改余额 account.balance -= money print(" 余额为: " + str(account.balance)) else: print(threading.current_thread().name + "取钱失败!余额不足") # 进行解锁 lock.release() # 创建一个账户,银行卡id为8888,存款1000元 acct = Account("8888" , 1000) # 模拟两个对同一个账户取钱 # 在主线程中创建一把锁 lock = threading.Lock() threading.Thread(name="窗口A", target=withdraw , args=(acct , 800)).start() threading.Thread(name="窗口B", target=withdraw , args=(acct , 800)).start()Lock与Rlock的区别区别一: Lock 被称为原始锁,一个线程只能请求一次;RLock 被称为重入锁,可以被一个线程请求多次,即锁中可以嵌套锁。import threading def main(): lock.acquire() print("第一道锁") lock.acquire() print("第二道锁") lock.release() lock.release() if __name__ == "__main__": lock = threading.Lock() main()
我们会发现这个程序只会打印"第一道锁",而且程序既没有终止,也没有继续运行。这是因为 Lock 锁在同一线程内第一次加锁之后还没有释放时,就进行了第二次acquire 请求,导致无法执行release ,所以锁永远无法释放,这就是死锁。如果我们使用RLock 就能正常运行,不会发生死锁的状态。 区别二:当 Lock 处于锁定状态时,不属于特定线程,可在另一个线程中进行解锁释放;而RLock 只有当前线程才能释放本线程上的锁,不可由其他线程进行释放,所以在使用RLock 时,acquire 与release 必须成对出现,即解铃还须系铃人。import threading def main(): lock.release() print("在子线程解锁后打印") if __name__ == "__main__": lock = threading.Lock() lock.acquire() t = threading.Thread(target=main) t.start()
在主线程中定义 Lock 锁,然后上锁,再创建一个子线程t 运行main 函数释放锁,结果正常输出,说明主线程上的锁,可由子线程解锁。
如果把上面的锁改为 RLock 则报错。在实际中设计程序时,我们会将每个功能分别封装成一个函数,每个函数中都可能会有临界区域,所以就需要用到RLock 。 import threading import time def fun_1(): print("开始") time.sleep(1) lock.acquire() print("第一道锁") fun_2() lock.release() def fun_2(): lock.acquire() print("第二道锁") lock.release() if __name__ == "__main__": lock = threading.RLock() t1 = threading.Thread(target=fun_1) t2 = threading.Thread(target=fun_1) t1.start() t2.start()
一句话总结就是 Lock 不能套娃,RLock 可以套娃;Lock 可以由其他线程中的锁进行操作,RLock 只能由本线程进行操作。
以上是今天分享的一部分内容。之前我整理了最新的java python 爬虫等编程学习资料+视频,关注我,评论666免费分享给大家!
华为机器视觉张爱军三个万物定义智能世界第四届中国人工智能安防峰会作者李溪编辑余快2021年12月11日,由雷峰网AI掘金志主办的第四届中国人工智能安防峰会,在深圳正式召开。本届峰会以数字城市的时代突围为主题,会上代表城市AIoT的14家标杆企业
马光远中国将成全球数字经济的最大赢家中新经纬12月21日电21日,由中国新闻社中新经纬主办,北京大学国家发展研究院联合主办的财经中国2022V峰会创新的力量在线上举行。经济学家马光远认为,中国在数字经济未来竞争方面有
美国全面围堵华为,中国却不能禁售苹果,背后关系网太复杂随着华为在5G领域崭露头角之后,让美国都心有余悸,因为眼看在5G领域,华为所拥有的技术,似乎要远超本土通讯企业。所以美国不得不将华为列入实体制裁清单之中,不仅要限制华为在通信基站的
中国北斗卫星什么时候才可以民用?谢谢邀请。我们先梳理一下北斗的发展历史,中国的卫星导航系统起步其实不晚,70年代,中国开始研究卫星导航系统的技术和方案,但之后这项名为灯塔的研究计划被取消。96年台海危机时,美国在
网站服务架构服务器划分对于访问量大的网站而言,将网站的各个部分拆分分别部署到不同服务器上是很有必要的。例如将图片和web站点分开。一般而言,在网站的整个服务器部署上分为如下几种类型文件服务器一
华为被制裁这两年,手机圈的市场现状如何?大家都知道,麒麟9000是华为目前最后的一颗处理器,也就是从这里开始,华为全方面被制裁,支持5G手机是卖一部少一部。自己家的其他系列也被分销出去,中邮,鼎桥,Hinova等。由于市
专做婚庆的团队,该怎么做推广?你有没有什么成功案例啊,或者是非常好评的活动现场,或者接过什么公司的年会啊什么的,如果你们专业素养不过硬的话,你早晚得破产。如果你有成功案例,那么你离成功只差一个靠谱的运营团队,把
8388元跌至1629元,双1200万IP67,经典iPhone二手机沦为千元机声明原创不易,禁止搬运,违者必究!从8388元跌至1629元,是怎样一个概念?手机市场的更新换代是非常快的,因此手机的保值度也越来越低了。在这种情况下,一些消费者也开始转变了,不热
华为Nova9手机登陆巴拉圭已开启预售南美侨报网编译边慧报道华为(Huawei)近日在巴拉圭推出了其最新手机产品Nova9,该新品于12月20日在巴拉圭进行预售,正式开售日期定为12月27日。巴拉圭国家报报道,在亚松森
无人机领域优等生大疆距离无人驾驶可能只差一部手机说起无人机产品,相信没有人会不知道大疆,自消费级无人机面世以来,大疆在同行业中的发展可谓一骑绝尘。从2006年的4人小作坊到2012年首款产品大疆精灵问世,如今在消费级无人机市场上
以现在地球的交通工具,在盾牌座UY上走一圈要多久?距离地球约5100光年的盾牌座UY,是目前人类在宇宙中发现的体积最大的一颗恒星。它的体积相当于45亿颗太阳,也就是说它的直径大约是太阳的1650倍,因此周长也是太阳的1650倍。而