ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PyCharm如何同时运行多个程序?四种多开方案与配置技巧

PyCharm如何同时运行多个程序?四种多开方案与配置技巧 如果你在PyCharm里点完一个Run紧接着去点另一个脚本发现上一个程序莫名其妙被停了恭喜你你不是一个人——这个问题每隔几天就会在一些技术群里出现一次“PyCharm是不是一次只能运行一个程序”别急答案是PyCharm完全可以同时运行多个程序而且有好几种玩法只是默认设置看起来像“单程序模式”把很多人给带偏了。这篇帖子我会从最底层的逻辑讲起然后给出不同场景下的多开方案最后带你把一套真实的“API服务任务进程报表任务”组合跑起来。不管你是刚照着安装教程装好IDE的新手还是用了一两年的老用户只要需要在本地同时跑服务、脚本和任务这篇都值得存一下。1. 为什么点一次Run上一个程序就被“顶”掉了1.1 先了解PyCharm默认做了什么要理解这个现象得先看PyCharm的运行机制。你写代码时点右上角绿色三角或者右键菜单里的Run实际启动的是一个叫“运行配置Run Configuration”的东西。它由三部分组成哪一个脚本、用哪个解释器、带什么参数和环境变量。PyCharm的默认策略是如果同一个运行配置已经处于运行状态你又点了它IDE会认为你想“重新启动”于是先把旧的实例停掉再启动一个全新的。这个行为在PyCharm里叫Rerun看起来很智能但也正是它让很多人以为“只能跑一个程序”。但注意这个“顶掉”只针对同一个配置。A配置在跑你切换到B配置再RunA不会退出。Run窗口最底部的运行面板里每个配置对应一个独立的Tab切来切去互不影响。你可以做个小实验先右键运行一个简单的a.py随便写个while True加sleep再运行b.py切回Run窗口观察两个Tab都在a.py的输出还在一行一行滚。只要a.py没被手动停止它一直活着。所以与其说“只能跑一个程序”不如说PyCharm默认会帮你管理资源避免同一个脚本被重复启动导致系统扛不住。1.2 不是限制是UI策略如果看操作系统层面就更清楚了。每次运行一个Python脚本本质上是启动了一个独立的python解释器进程。你在终端里敲python a.py和在PyCharm里点Run最终做的事情是一样的都是创建一个新进程。PyCharm只是个工具它不会从底层限制你只能创建一个Python进程。只要你愿意你可以同时创建几十个进程机器扛不扛得住另说。PyCharm做的只是界面层的工作把每个进程的标准输出、错误输出收集到右侧的Run窗口里。打个比方这就像同一个文件管理器里可以同时打开多个窗口。文件管理器默认并不会因为你新开一个窗口就把之前的窗口全关了但如果某个窗口自己提供了“重新打开并覆盖”的菜单项那只是这个菜单项的行为不代表文件管理器只支持一个窗口。PyCharm的Rerun策略就是这样一个覆盖行为。识别了这一点“只能跑一个”的错觉就会彻底消失。2. 同时运行多个程序的4种办法由浅入深2.1 不同脚本并行右键Run就是最朴素的办法最朴素也最好用的方案就是让不同脚本使用不同的运行配置逐个启动。PyCharm对每个脚本右键Run时会自动为你创建一个以脚本文件名命名的配置。所以你只需要在项目里把两个脚本分别右键运行PyCharm自动建好配置并各自启动。以后就算你想在A脚本运行期间重跑B脚本直接切到B配置再点RunA不会受任何影响。具体操作流程是这样的在项目窗口中右键第一个脚本选择 Run xxx或者直接打开脚本后点右上角的运行按钮。用同样方法运行第二个脚本、第三个脚本。把鼠标移动到底部Run窗口上方会看到多个Tab点击任意Tab查看对应进程的输出。需要停止某一个时先激活对应Tab再点左上角红色方块Stop。这个方法适合什么情况最常见的场景是本地联调你既要跑一个API服务又要跑一个数据处理脚本还要起一个定时任务。三个模块是同一个项目的不同部分但它们依赖彼此在线必须同时活着。用这种方式每个模块都有自己的输出窗口日志互不干扰排查问题也方便。2.2 同一个脚本多开先勾选 Allow parallel run同一脚本多开情况就有点不一样了。比如你要测试同一个爬虫脚本并发跑5个实例时的表现或者想让同一个服务脚本监听两个不同的端口。这时候脚本是同一个但实例需要多个。默认情况下PyCharm会用旧的把新的顶掉所以要动手改一下配置。进入 Run Edit Configurations...左侧选中对应配置在 Execution 或者 General 区域找到 Allow parallel run把它勾上。保存后再运行同一个配置PyCharm就不再停旧实例而是直接新起一个并排的Tab。这个开关就是为“同脚本多实例并行”准备的。如果不想动这个选项还有一招是复制配置。在Edit Configurations里右键某个配置选择Duplicate复制出来的配置名会带copy后缀。你只要改个名字比如server_9001、server_9002然后分别设置不同的端口环境变量再逐个运行就行。复制配置本质上就是新建了一个独立的“说明书”PyCharm会把它们完全当成两个不同的程序来管理。我实际用下来更喜欢复制因为Tab名称一眼就能区分不同实例之间不会混淆。注意Allow parallel run 是一个配置级别的开关。如果业务上确实不需要多实例别随手全勾上否则一键重跑很容易开出一堆进程IDE反应变慢、日志满天飞反而得不偿失。2.3 代码内部编排subprocess 和 multiprocessing把多进程管理下沉到代码里适合任务型场景。如果“多个程序”只是同一个业务系统里需要并行处理的子任务没必要在IDE上开一堆Tab直接在代码里用subprocess或multiprocessing把进程拉起来更可控。先看subprocess它适合从主程序里把其他脚本当独立服务拉起来import subprocess # 同时启动两个脚本Popen不会阻塞主程序 p1 subprocess.Popen([python, server.py]) p2 subprocess.Popen([python, worker.py]) print(两个子进程已启动主程序继续执行) # 需要结束时可以 p1.terminate()、p2.terminate()再看multiprocessing它适合同一个程序里并行跑多个带任务的函数进程之间是真正并行而不是线程切换出来的“并发”效果import multiprocessing import time def worker(name): for i in range(5): print(f{name} 正在处理第 {i 1} 条数据) time.sleep(1) if __name__ __main__: tasks [任务A, 任务B, 任务C] processes [] for t in tasks: p multiprocessing.Process(targetworker, args(t,)) p.start() processes.append(p) for p in processes: p.join()注意Windows下multiprocessing代码必须放在ifname main保护块里。原因是Windows创建子进程时会重新导入主模块如果不加保护子进程会再次执行“启动子进程”的代码很快引发递归错误进程数直接爆炸。这个坑我后面还会细说。subprocess.Popen在这个场景里不用保护因为它是直接拉起外部脚本不涉及重新导入当前文件。2.4 一键启动多个程序Compound 复合配置最后推荐一个很多人没用过的特性Compound复合配置。它的作用是把多个已存在的运行配置打包成一个一次点击全部启动。配置路径Run Edit Configurations... 左上角号 Compound然后在右侧把之前创建好的配置加入列表。保存后运行这个复合配置列表里的配置会分别在各自的Run Tab里启动效果等于你手动挨个点了多次Run但省去了切换和记忆顺序的功夫。它适合搭建本地开发环境。比如我的一个项目里后端API、任务消费进程和前端构建脚本经常要一起跑单独记忆三个配置的启动顺序很容易漏。做成一个Compound之后每天开工只要点一次运行三个进程一起上来。不过它有个局限只是“同时启动”不关心配置之间的依赖关系也不会等某个服务就绪再启动下一个。如果A服务没起来B服务启动时去请求A服务日志会直接报错你得自己决定要不要按顺序启动或者在代码里做重试。它不是docker-compose不会帮你管编排这一点要有预期。3. 运行配置里这几个关键设置决定你能不能优雅多开3.1 一份配置字段对照表多开能不能跑得顺很大程度上取决于运行配置里几个字段填得对不对。我整理了一份对照给你按图索骥设置项位置作用多开时的建议Allow parallel runExecution 区域不同版本可能叫General控制同一配置能否同时跑多个实例并发测试或同脚本多实例时需要勾选Script parametersScript 路径下面的参数框在启动时向脚本传入命令行参数代码里通过sys.argv读取用它传实例编号、输入文件避免硬编码Environment variablesEnvironment 区域注入环境变量代码通过os.environ读取多实例时用它区分端口、实例ID、日志路径Working directoryEnvironment 区域指定进程工作目录影响相对路径统一设为项目根目录或数据目录否则相对路径经常报FileNotFoundErrorPython interpreterPython 解释器区域决定用哪个解释器运行代码尽量统一用项目虚拟环境避免不同实例依赖不一致这五个字段里多开场景下最容易出问题的其实是Working directory和Environment variables。很多人把脚本放在子目录默认的工作目录却是项目根目录代码里用相对路径读配置就会失败多实例同跑时如果不通过环境变量区分端口第二个实例启动就会直接报“端口已占用”。这些坑如果你看过这张表再配置基本能避开。3.2 命名规范和配置管理多开之后你马上会发现一个新的问题Run窗口的Tab越来越多分不清谁是谁。PyCharm的Tab名称默认跟随配置名所以配置命名直接决定了你的识别效率。我的建议是采用“脚本名_用途_端口/实例号”的结构比如server_api_9001、worker_consumer_02、report_task_A。这样哪怕同时开着六七个Tab一眼扫过去就知道哪个对应哪个。配置的复制和删除也很常用。在Edit Configurations里选中某个配置右键可以Duplicate复制出来的配置继承原参数只需要微调名称和环境变量就能快速产生一个变体不用重新填一堆字段。删除配置也不用担心配置只是PyCharm用来记录“怎么运行这个文件”的说明书删除它并不会影响到实际的.py脚本文件。如果你希望所有新配置默认带一些公共环境变量可以看看自己的PyCharm版本里有没有对应的Default/Python配置模板直接修改模板以后新建配置就自动带上了。找不到模板也不用费劲偷懒的做法是复制一个已有配置再改效果一样。4. 实操实录一台机器同时跑API服务、任务进程和报表任务4.1 场景设定为什么需要三个程序同时跑光讲理论还是不够直观我拿一个实际场景带大家走一遍完整流程。假设我手头有个小项目需要同时跑三个角色一个API服务对外提供数据、一个任务进程定时检查服务状态、一个报表进程定期打印运行统计。这三个角色彼此独立但又属于同一套业务流程只有全部在线才能把整个链路跑通。先准备三个脚本。第一个是server.py用Flask起一个最简API服务from flask import Flask, jsonify import os app Flask(__name__) port int(os.environ.get(APP_PORT, 9001)) app.route(/health) def health(): return jsonify({status: ok, port: port}) if __name__ __main__: app.run(host127.0.0.1, portport)第二个是worker.py它每隔几秒去请求一次上面那个服务的健康检查接口import time import requests url http://127.0.0.1:9001/health while True: try: r requests.get(url, timeout3) print(fworker 检查服务状态HTTP {r.status_code}) except Exception as e: print(fworker 检查服务异常{e}) time.sleep(3)第三个是report.py它定期打印一条运行统计日志并且通过环境变量RUN_ID区分实例import time import os from datetime import datetime run_id os.environ.get(RUN_ID, 1) while True: now datetime.now().strftime(%H:%M:%S) print(f[report-{run_id}] {now} 统计任务运行中) time.sleep(5)这里要注意运行前记得先装依赖三个脚本用到的库一共就两个Flask和requests。直接pip install flask requests就行。端口我用9001避开常见的8000和5000减少被本地其他服务占用的概率。4.2 配置与启动的完整过程接下来打开Run Edit Configurations...点左上角号新建三个Python配置分别命名为API_Service、Task_Worker、Report_TaskScript paths分别指向上面三个脚本。第一步在API_Service配置里找到Environment variables填入APP_PORT9001。这样代码里的os.environ.get(APP_PORT, 9001)就能读到9001这个值如果你有第二个API实例就可以把环境变量改成9002代码一行都不用动。第二步在Report_Task配置里Environment variables填RUN_ID1。Task_Worker这一版暂时不需要特殊环境变量因为它在代码里写死了访问9001端口。第三步依次运行。先选中API_Service点运行按钮它会启动Flask服务并显示监听9001端口的日志再选择Task_Worker运行worker会开始每隔3秒打印一次HTTP状态码最后选择Report_Task运行三个程序同时在线。这时候切到Run窗口你会看到三个Tab输出互不干扰。第四步为了演示同脚本多开我们把Report_Task配置右键复制一份名字改成Report_Task_2Environment variables改成RUN_ID2。运行这个新配置后Run窗口会出现第四个Tab两个报表进程同时输出但每条日志前缀分别是report-1和report-2一眼就能区分。这时候顺便验证一下前面说的“顶掉”逻辑如果在Report_Task运行期间你再直接运行Report_Task没勾Allow parallel run的话旧的report-1实例就会被顶掉而API_Service和Task_Worker完全不受影响。这个实验做完你对PyCharm的并行机制应该就有很直观的感受了。4.3 并行调试和资源占用观察如果你在某个实例里发现了bug可以改用Debug按钮而不是Run按钮。PyCharm支持同时挂多个调试会话Debug窗口同样按Tab区分。你可以先Debug API_Service再Debug Task_Worker两个调试会话都在。切换断点时要先确认当前激活的是哪个Tab因为断点命中的会话会自动弹出对应Tab如果是另一个会话的断点看起来就像“乱跳”其实只是IDE在帮你定位。资源观察方面运行三个进程后打开任务管理器Windows或活动监视器macOS你会看到多个python进程同时存在。PyCharm只是其中几个进程的“宿主”和管理面板真正干活的是这些系统进程。如果机器明显变卡优先停掉不重要的Tab或者给负载高的任务想办法优化。本机多开的基本盘就是这样机器配置高就多开配置一般就克制一点。提示PyCharm的Stop按钮只停止当前激活的那个会话不是一键停全部。想批量关闭时可以右键Run窗口里的某个Tab选Close或者从运行配置下拉框里逐个Stop。别以为点一下红色方块所有程序都退了这是很多人多开之后的第一个误操作。5. 高频问题排查表和踩坑笔记5.1 高频问题排查表多开时你会碰到的麻烦基本就集中在下面这张表里。我按“现象、原因、解决方案”三个维度整理遇到问题照着查现象原因解决方案再次运行同一个脚本时旧的立刻退出同一配置默认Rerun会先停旧再启新勾选Allow parallel run或复制配置用不同名称新起的程序报端口被占用两个实例用了同一个端口用Environment variables给每个实例不同端口比如APP_PORT9001、9002多个实例输出相似分不清谁是谁Tab名相同或日志没带标识配置名改清晰代码里打印实例ID用logging而不是print程序明明停止但端口还占着进程可能没被真正kill或还有子进程残留在任务管理器/活动监视器里找到对应python进程结束检查Compound里是否有遗留子进程断点总是同时命中多个实例所有并行实例共享同一个断点设置条件断点或先停掉不需要调试的会话运行多个程序后电脑卡顿严重进程多、内存或CPU超载减少并行数量用虚拟环境避免依赖混乱及时停掉空闲Tab前两条最常出现。尤其是端口占用多开服务型程序时几乎一定遇到只要你给每个实例分配不同环境变量就能解决。日志识别问题也常见但只要配置命名规范、打印带实例标识基本就根治了。5.2 几个值得记住的实战教训第一个教训来自multiprocessing和Windows的组合。我在Windows下写过一段很简单的并行任务脚本忘了加ifname main然后在PyCharm里一运行进程数像裂变一样疯涨几秒内从1个涨到30多个只能去任务管理器一个个结束。后来在Linux下试同样的代码没事但Windows的spawn机制就是这样子进程会重新导入主脚本没保护就会无限递归。这个锅不是PyCharm的但多程序并行时最容易碰上建议你把它写进自己的checklist。第二个教训是日志问题。多开几个程序之后如果大家共用同一个日志文件或者只靠print输出到各自的Run Tab排查问题时很难把因果关系串起来。我的经验是每个实例至少打印出“我是谁”标识配置名也好、RUN_ID也好、进程PID也好总能帮你快速定位。更进一步给每个实例设置独立的日志文件比如report-1.log、report-2.log谁出了问题就翻谁的日志省去从头到尾扫控制台的痛苦。第三个教训是关于停止会话。刚多开那会儿我总以为Stop按钮是全停结果好几次点了Stop其他程序还在默默跑任务该执行完还在执行完。后来养成习惯停之前先看激活的Tab是不是目标进程再动手。同时开多了就定期在Run窗口清理一下把已经运行完毕的灰色Tab关掉保持工作区整洁不然几十个Tab堆在那里光找位置都费眼神。现在我自己开PyCharm干活默认就不只开一个运行Tab服务、任务、脚本经常同时挂着。刚开始多开那阵子我也踩过不少坑最典型的就是在Windows下跑multiprocessing忘了加main保护眼看进程数一路涨到好几十只能一个个去任务管理器里结束。后来养成了习惯每个配置复制一份、环境变量区分实例、日志带标识多开就再也不会乱了。你也不用一次性掌握全部技巧先从今天第一个方案试起把多个脚本同时跑起来感受一下就回不去了。
返回列表