Snakemake使用Slurm模式时Python代码输出无法实时显示
问题描述
近期使用Snakemake时遇到输出同步问题:直接执行snakemake -c1运行调用spladder的规则时,Python代码中的print()输出能实时显示;但启用Slurm模式(snakemake -j1 --use-conda --slurm)后,这些Python输出要等任务结束或失败才会显示,而STAR等非Python程序的输出却能实时写入Slurm日志。相关规则代码如下:
rule spladder: input: genomes = [f"../ressources/genomes/{genome}/genomic.gtf" for genome in accessions['genome_id'].unique()], bams = [f"data/alignments/{rsa}/{rsa}_Aligned.sortedByCoord.out.bam" for rsa in accessions.index] output: [f"data/spladder/{genome}/merge_graphs_mutex_exons_C3.pickle" for genome in accessions['genome_id'].unique()] threads: 20 resources: mem_mb=1024*20, runtime=60*8 run: print("========RUNNING JOB SPLADDER=========") print("\n\n\n") print(input.genomes) for genome in input.genomes: genome_id = re.search(r'genomes/(.+?)/', genome).group(1) filtered_accessions = accessions[accessions['genome_id'] == genome_id] rsa_ids = filtered_accessions.index.values if len(rsa_ids) > 0: bam_files = [f"data/alignments/{rsa}/{rsa}_Aligned.sortedByCoord.out.bam" for rsa in rsa_ids] bam_files = ",".join(bam_files) print(f"running spladder for {genome} with {bam_files}") cmd = fr""" mkdir -p data/spladder/{genome_id} spladder build --set-mm-tag nM --bams {bam_files} --annotation {genome} \ --outdir data/spladder/{genome_id} --parallel {threads} """ shell(cmd)
解决方案
问题根源是Python默认会缓冲标准输出(stdout),在Slurm的非交互式任务环境中不会自动实时刷新,而系统级工具(如STAR)通常采用行缓冲或无缓冲机制,因此能实时输出。以下是几种可行的解决方法:
1. 强制Python输出实时刷新
修改所有print()语句,添加flush=True参数,让Python立即刷新输出缓冲区:
print("========RUNNING JOB SPLADDER=========", flush=True) print("\n\n\n", flush=True) print(input.genomes, flush=True) # 后续所有print都加上flush=True参数
也可以在run块开头全局设置无缓冲输出,后续print无需重复加参数:
run: import sys # 设置stdout为行缓冲模式,自动实时刷新 sys.stdout = open(sys.stdout.fileno(), 'w', buffering=1) # 剩余代码不变
2. 利用Snakemake日志字段重定向输出
给规则添加log字段指定日志文件,将Python的stdout/stderr重定向到该文件,Slurm会实时同步文件内容:
rule spladder: input: genomes = [f"../ressources/genomes/{genome}/genomic.gtf" for genome in accessions['genome_id'].unique()], bams = [f"data/alignments/{rsa}/{rsa}_Aligned.sortedByCoord.out.bam" for rsa in accessions.index] output: [f"data/spladder/{genome}/merge_graphs_mutex_exons_C3.pickle" for genome in accessions['genome_id'].unique()] threads: 20 resources: mem_mb=1024*20, runtime=60*8 log: "logs/spladder_{wildcards.genome_id}.log" # 添加日志字段 run: import sys # 重定向stdout和stderr到日志文件 sys.stdout = sys.stderr = open(snakemake.log[0], 'w') # 后续所有print和shell命令输出都会写入日志文件,可实时查看 print("========RUNNING JOB SPLADDER=========") # 剩余代码不变
3. 设置PYTHONUNBUFFERED环境变量
在调用Snakemake时添加环境变量,强制Python全程无缓冲输出:
PYTHONUNBUFFERED=1 snakemake -j1 --use-conda --slurm
也可以在规则中通过envvars字段全局设置:
rule spladder: # 其他字段不变 envvars: ["PYTHONUNBUFFERED=1"]
内容的提问来源于stack exchange,提问作者Niklas E.
相关产品推荐
相关产品推荐

