jupyter内核崩溃

最近在做用k-mer评估基因组规模的任务,其中一个局部程序,想偷懒,直接在jupyter中跑了下结果,想看看这一小步处理如何,结果没想到内核崩溃了!

这一步我的草稿代码如下:

import pandas as pd
import glob
from pathlib import Path
def kmer_dict(jf_txt_file,top_m):"""Args:jf_txt_file (str): 主要是dump命令的输出文件路径top_m(int):从k-mer文件中要提取的top几个k-merFun:从输入文件中返回该k-mer文件中top M的k-mer的字典,key为k-mer,value为该k-mer的计数,按照count的降序整理,返回该dict,同时输出为tsv格式的文件后续如果要使用输出文件,可以继续使用pandas等进行处理;如果要使用返回的字典变量,可以直接使用该函数的返回值  """kmer = pd.read_csv(jf_txt_file,sep=" ",header=None,names=["mer","count"])# 按照降序排列,顺便只看前top_m行kmer = kmer.sort_values(by="count",ascending=False).head(top_m)# 输出为tsv格式文件kmer.to_csv(jf_txt_file.replace(".txt",f"_{top_m}.tsv"),sep="\t",header=True)# 同时返回每一个k-mer的字典kmer_dict = dict(zip(kmer["mer"],kmer["count"]))return kmer_dict# 对于两个基因组的所有k-mer文件,使用前面定义的kmer_dict函数来提取top M的k-mer字典
Q1_dir = "/data1/project/omics_final/Q1"
kmer_files = glob.glob(f"{Q1_dir}/*.txt")kmer_results = {}
for each_kmer in kmer_files:each_kmer_name = Path(each_kmer).stem  # 获取文件名,不包含路径和扩展名print(f"处理文件: {each_kmer_name}\n")# 此处对于每一个k-mer文件,提取其前10个对应的k-mer,并将结果输出为对应的变量kmer_results[each_kmer_name] = kmer_dict(each_kmer,top_m=10)print(f"存储为: kmer_results['{each_kmer_name}']\n")

做的事情呢,其实很简单,就是用jellyfish count,在自己的测试基因组组装数据集上统计了一下k-mer,

然后用jellyfish dump命令,将统计结果,用python稍微处理一下整理成字典形式,存到一个字典中;

我测试的数据只有2个新组装的人类基因组,各自大小也就在3G左右,k-mer文件将近30个,每个大小不一,k小的文件才几M,k大的文件组合花样多,一般都几十G,

任务是在jupyter中跑的,结果爆了,推测是处理大量k-mer数据导致的内存或计算资源耗尽。

问题来了:

我放在后台跑,比如python xxx.py,肯定能够成功执行,比放在cell中稳妥多了;

但是我的变量已经return出来了,我肯定还是想之后能够直接在python环境中访问的,虽然我用pandas再将结果文件读进去都一样的内容,但是太麻烦了,我太懒了。

有没有什么一般的策略,不仅仅局限于这个问题,就是可能会导致内核崩溃的稍微大型计算任务,

我又想像放在后台稳定运行一样能够跑完这个任务,又希望就放在cell中跑,跑完之后直接访问结果变量?

法1:使用批处理 + 保存中间结果

其实就是很简单,分批嘛,batch,我一次处理30多个数据多麻烦,每次只处理一小部分,比如说5个,如果还是太大了,就3个文件一处理;

重要的是我要及时将结果文件保存,所以还是输出到硬盘上了(其实理论上来讲,那我还是可以全部都放在后台运行,然后在代码上添加每一步都保存的命令,这样我还是可以保证结果变量能够访问);

总之一小批一小批的运行并pickle输出到硬盘中保存,然后下一次运行判断哪些已经跑过了(这里比较重要,如果内核又崩溃了,我们就需要再次重启内核在cell中跑,但是已经跑过的结果就不用再跑了)。

当然,有人会担心如果我每次跑的时候,保存保存了一部分然后内核就崩溃了,那么文件系统检查的时候如果重新加载了这个变量,然后它一看如果发现我加载的字典中已经有这个结果了,哪怕是一部分,会不会直接跳过,然后导致我其实这个应该被关注留意的结果其实并没有得到重视?

比如说下面的这里?

其实这个问题我也考虑到了,所以我要确保每次保存结果的时候,都要完整保存或者说保存命令执行成功了,我才打印进程提醒:

比如说下面这里的进程——》

代码整体逻辑如下:

import pandas as pd
import glob
import pickle
import os
from pathlib import Path
import gcdef kmer_dict(jf_txt_file, top_m):"""k-mer处理函数,添加错误处理"""try:print(f"  正在读取文件: {jf_txt_file}")kmer = pd.read_csv(jf_txt_file, sep=" ", header=None, names=["mer", "count"])print(f"  数据形状: {kmer.shape}")kmer = kmer.sort_values(by="count", ascending=False).head(top_m)# 输出TSV文件output_file = jf_txt_file.replace(".txt", f"_{top_m}.tsv")kmer.to_csv(output_file, sep="\t", header=True, index=False)# 返回字典kmer_dict = dict(zip(kmer["mer"], kmer["count"]))# 清理内存del kmergc.collect()return kmer_dictexcept Exception as e:print(f"  处理文件 {jf_txt_file} 时出错: {e}")return Nonedef process_kmer_files_safely():"""安全处理k-mer文件,支持断点续传"""Q1_dir = "/data1/project/omics_final/Q1"kmer_files = glob.glob(f"{Q1_dir}/*.txt")# 结果保存文件results_file = f"{Q1_dir}/kmer_results.pkl"# 如果已有结果文件,先加载if os.path.exists(results_file):print(f"加载已有结果: {results_file}")with open(results_file, 'rb') as f:kmer_results = pickle.load(f)print(f"已加载 {len(kmer_results)} 个结果")else:kmer_results = {}print(f"找到 {len(kmer_files)} 个txt文件")# 处理每个文件for i, each_kmer in enumerate(kmer_files, 1):each_kmer_name = Path(each_kmer).stem# 跳过已处理的文件if each_kmer_name in kmer_results:print(f"[{i}/{len(kmer_files)}] 跳过已处理文件: {each_kmer_name}")continueprint(f"[{i}/{len(kmer_files)}] 处理文件: {each_kmer_name}")try:result = kmer_dict(each_kmer, top_m=10)if result is not None:kmer_results[each_kmer_name] = resultprint(f"  成功处理,获得 {len(result)} 个k-mer")# 每处理5个文件保存一次结果if i % 5 == 0:with open(results_file, 'wb') as f:pickle.dump(kmer_results, f)print(f"  已保存中间结果到: {results_file}")else:print(f"  处理失败,跳过")except Exception as e:print(f"  发生异常: {e}")continue# 强制垃圾回收gc.collect()# 保存最终结果with open(results_file, 'wb') as f:pickle.dump(kmer_results, f)print(f"\n最终结果已保存到: {results_file}")print(f"总共处理了 {len(kmer_results)} 个文件")return kmer_results# 运行处理
try:kmer_results = process_kmer_files_safely()
except Exception as e:print(f"处理过程中发生错误: {e}")# 尝试加载已保存的结果results_file = "/data1/project/omics_final/Q1/kmer_results.pkl"if os.path.exists(results_file):with open(results_file, 'rb') as f:kmer_results = pickle.load(f)print(f"加载了已保存的结果: {len(kmer_results)} 个文件")

真实运行情况:

所以3个还是消耗太大了,对于我上面的执行逻辑,干脆就直接改为1,每运行1次就保存,当然我还是得蹲在前台一直看着这个代码的运行。

文件其实很多,我们先仔细看一下:

ls -lh | awk -F " " '{print $5}' | grep "G" | awk -F "G" '{print $1}' | sort | uniq

可以发现,其实最大的文件已经达到了50G了,比基因组规模3G大了十几倍,

其实运行了好几次了,都是17-mer这个文件就一直卡着,其实我们也可以另外直接在shell中awk处理好输出top M的文件,也没必要什么都在python中处理,不然吃不消。

法2:使用Jupyter的后台执行

# 在新的cell中运行
import threading
import timedef background_process():"""后台处理函数"""global kmer_results  # 使用全局变量try:kmer_results = process_kmer_files_safely()print("后台处理完成!")except Exception as e:print(f"后台处理出错: {e}")# 启动后台线程
processing_thread = threading.Thread(target=background_process)
processing_thread.daemon = True  # 设置为守护线程
processing_thread.start()print("后台处理已启动,您可以继续使用其他cell")
print("使用 processing_thread.is_alive() 检查处理状态")

其实就是多线程库threading的使用,主要函数继承前面的,主要改了点运行

法3:分批处理 + 内存优化

其实batch的想法还是和1一样的,只不过是多了个内存的监控强制优化

import pandas as pd
import glob
import pickle
from pathlib import Path
import gc
import psutil
import osdef get_memory_usage():"""获取当前内存使用情况"""process = psutil.Process(os.getpid())return process.memory_info().rss / 1024 / 1024  # MBdef process_kmer_batch(file_batch, batch_num):"""处理一批文件"""print(f"\n=== 处理批次 {batch_num} ===")print(f"内存使用: {get_memory_usage():.1f} MB")batch_results = {}for i, file_path in enumerate(file_batch, 1):filename = Path(file_path).stemprint(f"  [{i}/{len(file_batch)}] 处理: {filename}")try:# 检查内存使用memory_usage = get_memory_usage()if memory_usage > 4000:  # 超过4GB则强制清理print(f"    内存使用过高 ({memory_usage:.1f} MB),执行垃圾回收")gc.collect()result = kmer_dict(file_path, top_m=10)if result is not None:batch_results[filename] = resultprint(f"    成功,获得 {len(result)} 个k-mer")except Exception as e:print(f"    失败: {e}")continuereturn batch_resultsdef process_all_files_in_batches(batch_size=5):"""分批处理所有文件"""Q1_dir = "/data1/project/omics_final/Q1"kmer_files = glob.glob(f"{Q1_dir}/*.txt")print(f"总共找到 {len(kmer_files)} 个文件")print(f"将分 {len(kmer_files)//batch_size + 1} 批处理,每批 {batch_size} 个文件")all_results = {}# 分批处理for i in range(0, len(kmer_files), batch_size):batch = kmer_files[i:i+batch_size]batch_num = i//batch_size + 1batch_results = process_kmer_batch(batch, batch_num)all_results.update(batch_results)# 每批处理完后保存结果results_file = f"{Q1_dir}/kmer_results_batch_{batch_num}.pkl"with open(results_file, 'wb') as f:pickle.dump(batch_results, f)print(f"  批次结果已保存: {results_file}")# 强制垃圾回收gc.collect()print(f"  当前总结果数: {len(all_results)}")# 保存最终合并结果final_results_file = f"{Q1_dir}/kmer_results_final.pkl"with open(final_results_file, 'wb') as f:pickle.dump(all_results, f)print(f"\n处理完成!最终结果已保存: {final_results_file}")return all_results# 执行分批处理
kmer_results = process_all_files_in_batches(batch_size=3)

法4:访问已保存的结果

这个其实就是最原始的想法,全都放在后台,只保留全部运行之后的结果变量,执行过程当然是用到什么变量就得保存什么变量,还是保存为pkl格式。

当然,实际运行的时候,其实发现真的很耗费计算资源的任务,你放在cell中内核会崩溃,其实放在后台则是会被kill,其实都是同样有极大可能性失败的;

# 在任何时候都可以加载已保存的结果
import pickle
import osdef load_saved_results():"""加载已保存的结果"""Q1_dir = "/data1/project/omics_final/Q1"# 尝试加载最终结果final_file = f"{Q1_dir}/kmer_results_final.pkl"if os.path.exists(final_file):with open(final_file, 'rb') as f:results = pickle.load(f)print(f"加载最终结果: {len(results)} 个文件")return results# 如果没有最终结果,尝试加载中间结果intermediate_file = f"{Q1_dir}/kmer_results.pkl"if os.path.exists(intermediate_file):with open(intermediate_file, 'rb') as f:results = pickle.load(f)print(f"加载中间结果: {len(results)} 个文件")return resultsprint("没有找到已保存的结果")return {}# 加载结果
kmer_results = load_saved_results()# 查看结果概况
if kmer_results:print(f"加载了 {len(kmer_results)} 个文件的结果")print("文件列表:")for name in sorted(kmer_results.keys()):print(f"  {name}: {len(kmer_results[name])} 个k-mer")

所以,如果仅仅只是简单的文本文件处理,只要不涉及到非常复杂的数据处理,pandas能够简单应付的任务,还是直接用awk算了(也就是shell中批量处理得了)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/909361.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java企业技术趋势分析:AI应用的落地实践与未来展望

Java企业技术趋势分析:AI应用的落地实践与未来展望 开篇:技术趋势与市场需求 在当前快速发展的数字化时代,人工智能(AI)已经成为推动企业创新和效率提升的关键力量。Java作为企业级应用开发的主流语言,正…

每日Prompt:Steve Winter风格插画

提示词 世界摄影大师杰作,极简主义,Steve Winter风格,6只不同颜色的布偶猫围成一圈,看向镜头中心,仰天视角,天空背景,高品质细节,超精细CG,高分辨率,最佳品质…

Vue3 + Element Plus 获取表格列信息

在 Vue 3 和 Element Plus 中,可以通过以下步骤获取表格的列信息: 实现步骤: 使用 ref 绑定表格实例 通过表格实例的 store.states.columns 获取列数据 处理列信息(过滤隐藏列、处理嵌套表头等) 示例代码&#xf…

logger2js - JavaScript日志与调试工具库

logger2js - JavaScript日志与调试工具库 logger2js是一个功能强大的前端JavaScript日志与调试工具库,提供了丰富的日志输出、性能测试和代码调试功能。该库支持配置化引入,包含5种皮肤风格和丰富的API接口,如 a l e r t 增强方法、 alert增…

Stone 3D使用RemoteMesh组件极大的缩小工程文件尺寸

Stone 3D的工程文件tsp默认包含了场景中所有的对象和数据,这样的好处是tsp可以单独离线保存,但坏处是tsp文件通常偏大。 解决这个问题的方法是把外部glb模型文件通过RemoteMesh组件来加载。 首先创建一个空实体,然后给该空实体添加RemoteMe…

【深入剖析】攻克 Java 并发的基石:Java 内存模型 (JMM) 原理与实践指南

0.引言 理解 JMM (Java Memory Model - JMM) 是掌握 Java 并发编程的关键,它定义了多线程环境下,线程如何与主内存以及彼此之间交互内存数据。 核心目标: JMM 旨在解决多线程编程中的三个核心问题: 原子性 (Atomicity)&#xf…

【Three.js】初识 Three.js

Threejs介绍 我们开发 webgl 主要是使用 threejs 这个库,因为 webGL太难用,太复杂!但是现代浏览器都支持WebGL,这样我们就不必使用Flash、Java等插件就能在浏览器中创建三维图形。 threejs 它提供-一个很简单的关于WebGL特性的J…

【经验总结】ECU休眠后连续发送NM报文3S后ECU网络才被唤醒问题分析

目录 前言 正文 1.问题描述 2.问题分析 3.验证猜想 4.总结 前言 ECU的上下电/休眠唤醒在ECU开发设计过程中最容易出问题且都为严重问题,最近在项目开发过程中遇到ECU休眠状态下连续发送NM报文3S后才能唤醒CAN网络的问题,解决问题比较顺利,但分析过程中涉及到的网络休…

企业架构框架深入解析:TOGAF、Zachman Framework、FEAF与Gartner EA Framework

执行摘要 企业架构(EA)是一项至关重要的实践,它使组织能够协调其业务战略、运营流程和技术基础设施,以实现整体战略目标。企业架构框架作为结构化的方法论和综合性工具,旨在管理企业级系统的固有复杂性,提…

数字化动态ID随机水印和ID跑马灯实现教育视频防录屏

摘要:数字化动态ID随机水印和ID跑马灯技术可以有效保护数字教育资源。动态水印将用户信息随机显示在视频上且不可去除,能追踪录屏者并震慑盗版行为。ID跑马灯则自定义显示观看者信息,便于追踪盗版源头并提供法律证据。这些技术大幅增加盗版成…

< 自用文儿 腾讯云 VPS > Ubuntu 24 系统,基本设置

前言: 3 月份买的腾讯云的这台 VPS,刚发现现在退款,只能返回 0 元。测试应用已经迁移到JD,清除内容太麻烦,重装更简单。 因为配合政策,国内的云主机都有两个 IP 地址,一个内网,一个…

React ajax中的跨域以及代理服务器

Axios的诞生 为什么会诞生Axios?说到Axios我们就不得不说下Ajax。最初的旧浏览器页面在向服务器请求数据时,由于返回的是整个页面的数据,所以整个页面都会强制刷新一下,这对于用户来讲并不是很友好。因为当我们只需要请求部分数据…

HOT 100 | 73.矩阵置零、54.螺旋矩阵、48.旋转图像

一、73. 矩阵置零 73. 矩阵置零 - 力扣(LeetCode) 1. 解题思路 1. 使用两个数组分别标记每行每列是否有0,初始化全为False,遇到0就变成True。 2. 遍历矩阵,遇到0就将False改成True。 3. 再次遍历矩阵,更…

神经网络压缩

网络压缩技术学习笔记 以下笔记基于提供的 PDF 文件(tiny_v7.pdf),总结了网络压缩技术的核心概念、实现原理和方法,特别针对多模态大模型、空间智能以及未来智能体(Agent)和通用人工智能(AGI&a…

论索引影响性能的一面④ 索引失踪之谜【上】

梁敬彬梁敬弘兄弟出品 往期回顾 论索引影响性能的一面①索引的各种开销 论索引影响性能的一面②索引的使用失效 论索引影响性能的一面③ 索引开销与经典案例 开篇:DBA的深夜“寻人启事” 作为数据库的守护者,我们最信赖的伙伴莫过于“索引”。它如同一…

java集合(九) ---- Stack 类

目录 九、Stack 类 9.1 位置 9.2 特点 9.3 栈 9.4 构造方法 9.5 常用方法 9.6 注意点:循环遍历 Stack 类 九、Stack 类 9.1 位置 Stack 类位于 java.util 包下 9.2 特点 Stack 类是 Vector 类的子类Stack 类对标于数据结构中的栈结构 9.3 栈 定义&…

ARXML可视化转换工具使用说明

ARXML可视化转换工具 | 详细使用指南与说明 📝 前言 自上篇文章《聊聊ARXML解析工具:我们是如何摆脱昂贵商业软件的》发布以来,收到了众多朋友的关注和咨询,这让我倍感荣幸! 新朋友请注意:如果您还没有阅…

松胜与奥佳华按摩椅:普惠科技与医疗级体验的碰撞

在智能健康设备快速普及的今天,按摩椅已从奢侈品转变为家庭健康管理的重要工具。面对市场上琳琅满目的品牌,松胜与奥佳华凭借截然不同的发展路径,各自开辟出特色鲜明的赛道:前者以“技术普惠”理念打破高端按摩椅的价格壁垒&#…

一起学习Web 后端——PHP(二):深入理解字符与函数的使用

一、前言 在上一讲中,我们主要讲PHP的相关知识。本节我们将继续深入,学习: PHP 中各种语法字符、符号的含义与用法; PHP 中常用函数的种类、定义方式与实际应用。 这些知识是构建 Web 后端逻辑的基础,对于后期编写…

【Bluedroid】蓝牙启动之 GAP_Init 流程源码解析

蓝牙 GAP(通用访问配置文件)模块是蓝牙协议栈的核心组件,负责设备发现、连接管理及基础属性暴露等关键功能。本文围绕 Android蓝牙协议栈 GAP 模块的初始化流程与连接管理实现展开,结合代码解析其核心函数(GAP_Init、gap_conn_init、gap_attr_db_init)的功能逻辑,以及关…