影刀RPA 多线程基础:并发采集入门

发布时间:2026/9/12 0:13:04

影刀RPA 多线程基础:并发采集入门 影刀RPA 多线程基础并发采集入门署名林焱什么情况用什么RPA采集100个网页单线程一个个打开要30分钟。如果同时开5个线程6分钟就跑完了。多线程能显著提升IO密集型任务效率。场景推荐方式特点网页批量采集threading 队列简单易用CPU密集型计算multiprocessing绕过GIL限制大量并发请求ThreadPoolExecutor线程池管理怎么做一基础多线程importthreadingimporttime# 单线程对比deffetch_page(url):模拟采集一个网页print(f开始采集:{url})time.sleep(2)# 模拟网络请求耗时print(f完成采集:{url})returnf{url}的内容urls[https://example.com/page1,https://example.com/page2,https://example.com/page3,https://example.com/page4,https://example.com/page5,]# 单线程约10秒 print( 单线程 )starttime.time()results[]forurlinurls:results.append(fetch_page(url))print(f耗时:{time.time()-start:.1f}秒)# 多线程约2秒 print(\n 多线程 )starttime.time()threads[]results[None]*len(urls)# 预分配结果列表defworker(index,url):results[index]fetch_page(url)fori,urlinenumerate(urls):tthreading.Thread(targetworker,args(i,url))threads.append(t)t.start()# 等待所有线程完成fortinthreads:t.join()print(f耗时:{time.time()-start:.1f}秒)二线程池推荐拼多多店群自动化报活动上架fromconcurrent.futuresimportThreadPoolExecutor,as_completedimporttimedeffetch_page(url):采集网页time.sleep(1)# 模拟请求return{url:url,status:200,data:f{url}的内容}urls[fhttps://example.com/page{i}foriinrange(1,21)]# 使用线程池max_workers5# 最多5个线程同时运行results[]withThreadPoolExecutor(max_workersmax_workers)asexecutor:# 提交所有任务![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/73c282530e3f4f16a0b780322253ab24.png#pic_center)future_to_url{executor.submit(fetch_page,url):urlforurlinurls}# 按完成顺序获取结果forfutureinas_completed(future_to_url):urlfuture_to_url[future]try:resultfuture.result()results.append(result)print(f完成:{url})exceptExceptionase:print(f失败:{url}, 错误:{e})print(f\n共完成{len(results)}个任务)三线程安全的队列importthreadingimportqueueimporttime# 任务队列task_queuequeue.Queue()result_queuequeue.Queue()# 填充任务urls[fhttps://example.com/page{i}foriinrange(1,21)]forurlinurls:task_queue.put(url)defworker(worker_id):工作线程whileTrue:try:# 非阻塞获取任务超时退出urltask_queue.get(timeout1)exceptqueue.Empty:break# 执行任务try:time.sleep(0.5)# 模拟采集resultf[线程{worker_id}] 采集完成:{url}result_queue.put({url:url,status:success,data:result})exceptExceptionase:result_queue.put({url:url,status:error,error:str(e)})finally:task_queue.task_done()# 启动多个工作线程num_workers5threads[]foriinrange(num_workers):tthreading.Thread(targetworker,args(i,))t.start()threads.append(t)# 等待所有任务完成task_queue.join()# 收集结果results[]whilenotresult_queue.empty():results.append(result_queue.get())print(f完成{len(results)}个任务)forrinresults[:5]:print(r[data])四线程安全的数据操作importthreading# 线程安全的计数器classSafeCounter:def__init__(self):self._lockthreading.Lock()self._count0defincrement(self):withself._lock:self._count1returnself._countpropertydefvalue(self):withself._lock:returnself._count# 线程安全的列表classSafeList:def__init__(self):self._lockthreading.Lock()self._data[]defappend(self,item):withself._lock:self._data.append(item)defget_all(self):withself._lock:returnlist(self._data)# 使用counterSafeCounter()resultsSafeList()defworker(url):numcounter.increment()results.append(f第{num}个任务:{url})threads[threading.Thread(targetworker,args(furl{i},))foriinrange(10)]fortinthreads:t.start()fortinthreads:t.join()print(f计数:{counter.value})foriteminresults.get_all():print(item)完整流程并发采集管理器fromconcurrent.futuresimportThreadPoolExecutor,as_completedimportthreadingimporttimefromdatetimeimportdatetime# yd_input: urls, max_workers, delayurlsyd_input.get(urls,[])max_workersyd_input.get(max_workers,5)delayyd_input.get(delay,0.5)# 统计stats{total:len(urls),success:0,failed:0,start_time:datetime.now().strftime(%Y-%m-%d %H:%M:%S)}stats_lockthreading.Lock()results[]results_lockthreading.Lock()deffetch_url(url):采集单个URLtry:time.sleep(delay)# 控制请求频率# 这里放实际的采集逻辑# 例如用requests获取网页、解析数据等importrequests resprequests.get(url,timeout15,headers{User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64)})ifresp.status_code200:result{url:url,status:success,code:resp.status_code,length:len(resp.text),timestamp:datetime.now().strftime(%H:%M:%S)}withstats_lock:stats[success]1withresults_lock:results.append(result)returnresultelse:raiseException(fHTTP{resp.status_code})exceptExceptionase:withstats_lock:stats[failed]1result{url:url,status:error,error:str(e),timestamp:datetime.now().strftime(%H:%M:%S)}withresults_lock:results.append(result)returnresult# 执行并发采集start_timetime.time()withThreadPoolExecutor(max_workersmax_workers)asexecutor:futures{executor.submit(fetch_url,url):urlforurlinurls}completed0forfutureinas_completed(futures):completed1urlfutures[future]try:resultfuture.result()status_icon✓ifresult[status]successelse✗print(f{status_icon}[{completed}/{len(urls)}]{url})exceptExceptionase:print(f✗ [{completed}/{len(urls)}]{url}:{e})elapsedtime.time()-start_time stats[end_time]datetime.now().strftime(%Y-%m-%d %H:%M:%S)stats[elapsed]f{elapsed:.1f}秒print(f\n 采集完成 )print(f总计:{stats[total]}, 成功:{stats[success]}, 失败:{stats[failed]})print(f耗时:{elapsed:.1f}秒, 平均:{elapsed/len(urls):.2f}秒/个)yd_output{status:ok,stats:stats,results:results}有什么坑坑一多线程共享变量导致数据错乱现象多个线程同时写同一个列表结果列表长度不对或某些数据丢失。原因Python列表的append操作不是原子操作多线程同时写会导致数据覆盖。解决用锁保护共享数据importthreading# 错误不加锁# results []# def worker(url):# results.append(url) ❌ 多线程同时append可能丢数据# 正确用锁results[]lockthreading.Lock()defworker(url):withlock:results.append(url)# ✓ 同一时刻只有一个线程能写# 更好的方案用Queue线程安全importqueue result_queuequeue.Queue()defworker(url):result_queue.put(url)# ✓ Queue自带线程安全坑二线程数过多反而变慢现象把max_workers设为100结果比5个线程还慢。原因线程太多导致频繁的上下文切换开销大于并行收益。另外大量并发请求可能触发网站反爬导致请求被拒绝后重试。解决合理设置线程数TEMU店群矩阵自动化运营核价报活动# IO密集型任务网络请求线程数 CPU核数 × 2~5importos cpu_countos.cpu_count()# CPU核数optimal_workersmin(cpu_count*3,20)# 推荐3-20个线程# 不要无脑设大# max_workers 100 ❌ 太多反而慢# 根据目标网站承受能力调整# 小网站3-5个线程# 大网站10-20个线程# API接口看API的rate limit要求坑三主线程退出导致子线程中断现象主线程跑完了子线程还没完成就被强制退出结果不完整。原因默认子线程是守护线程daemonFalse主线程会等子线程完成。但如果设了daemonTrue主线程退出时子线程会被杀掉。解决确保正确等待子线程完成importthreading# 方案1用join等待推荐threads[]foriinrange(5):tthreading.Thread(targetworker,args(i,))t.start()threads.append(t)fortinthreads:t.join()# 等待每个线程完成print(所有线程完成)# 方案2用ThreadPoolExecutor自动等待fromconcurrent.futuresimportThreadPoolExecutorwithThreadPoolExecutor(max_workers5)asexecutor:futures[executor.submit(worker,i)foriinrange(5)]# with块结束时自动等待所有任务完成# 错误设为daemonTrue后不等待# t threading.Thread(targetworker, daemonTrue)# t.start()# # 不join主线程退出时子线程被杀 ❌坑四线程中的异常不会自动传播到主线程现象子线程报错了但主线程不知道以为全部成功。原因子线程的异常不会自动抛到主线程需要主动检查。解决用Future.result()获取异常或用try-except记录fromconcurrent.futuresimportThreadPoolExecutor,as_completeddefworker(url):iferrorinurl:raiseValueError(模拟错误)returnfsuccess:{url}urls[url1,error_url,url3]withThreadPoolExecutor(max_workers3)asexecutor:futures{executor.submit(worker,url):urlforurlinurls}forfutureinas_completed(futures):urlfutures[future]try:![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/768973b01eb040f38abbd2c293528c22.png#pic_center)# future.result()会重新抛出子线程中的异常resultfuture.result()print(f✓{url}:{result})exceptExceptionase:print(f✗{url}:{e})# 捕获子线程异常# 如果不用Future需要在worker函数内部catch异常defsafe_worker(url):try:# 实际逻辑returndo_work(url)exceptExceptionase:return{url:url,error:str(e)}# 返回错误信息而不是抛出
延伸阅读

更多相关文章

2026/9/10 23:25:23

从ChatGPT到AGI:2026年AI大模型的终极追问与未来幻想

国内用户访问提示:由于网络限制,OpenAI官网及Anthropic官网在国内无法直接访问。国内用户可通过镜像平台AIGCBAR体验ChatGPT、Claude等主流AI模型。该平台内置Auto模式与Thinking模式,思考程度提供标准和深度两档可选,支持国内邮箱…

2026/9/8 21:13:29

TMC7300+STM32L4S5ZI驱动有刷电机方案解析

1. 为什么选择TMC7300STM32L4S5ZI组合驱动有刷电机 有刷直流电机作为最传统的电机类型,至今仍在各类消费电子、工业设备和自动化系统中广泛应用。但要让这类电机实现精准稳定的转速控制,传统的H桥驱动方案往往面临效率低、发热大、响应慢等问题。这正是T…

2026/8/30 22:43:41

企业AI Agent与数据湖融合架构设计与优化实践

1. 企业AI Agent与数据湖的融合趋势最近两年,企业AI Agent正在从单纯的对话机器人向具备复杂决策能力的智能体演进。我在为三家制造业客户部署AI Agent时发现,传统的数据管道架构已经难以满足实时决策需求。某汽车零部件供应商的质检AI Agent需要同时处理…

2026/9/12 0:09:18

纯Java实现深度学习车牌识别:模型部署与调优全攻略

简介:这是一套基于深度学习、采用纯Java实现的智能车牌识别源码与模型包,支持14种中文车牌类型,面向Java技术栈开发者、算法工程师以及需要离线车牌识别能力的软件项目,可有效填补Java生态中轻量级深度学习推理落地的空白。资源共…

2026/9/12 0:09:18

MATLAB层次聚类实战:Excel数据驱动的可解释树状图构建

简介:本资源是一份面向数据科学初学者与MATLAB实践者的层次聚类(HC)可视化教学代码包,聚焦于解决实际数据分组分析与结果直观呈现问题,适用于课程设计、科研预研及算法原理理解等场景。压缩包为ZIP格式,大小…

2026/9/12 0:09:18

防红系统带后台无加密版:域名检测、切换与部署运维实践

简介:梦幻防红cos系统后台版是一套围绕网站防红场景设计的工具包,主要面向个人站长、网站管理员及中小型在线平台,用于解决DDoS攻击、恶意刷流量等导致的正常访问被拒绝问题。通过后台自定义防红接口,管理员无需深入底层代码即可调…

2026/9/12 0:04:17

【单片机毕业设计】基于 STM32 或 51 单片机的可变报警频率超声波检测系统设计 基于 STM32 或 51 单片机的按键阈值设置超声波测距仪设计(022907)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/9/10 16:39:38

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/10 11:16:38

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/12 0:04:17

MATLAB仿生优化框架:长鼻浣熊算法多策略融合实现

简介:本资源是一份面向智能优化算法研究者与MATLAB初学者的仿生智能算法实践代码包,聚焦于长鼻浣熊优化算法(COA)的多策略改进与性能验证。针对传统COA易陷局部最优、收敛精度不足等问题,作者融合Circle映射初始化提升…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 JavaWeb 的校园一卡通管理系统的设计与实现 基于 JavaWeb 的校园卡业务管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/12 0:04:17

【JAVA毕设源码分享】基于 Java 的图书馆借阅管理平台的搭建与实现 基于 Java 的图书馆综合管理系统(程序+文档+代码讲解+一条龙定制)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/10 12:32:02

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/10 15:49:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码