Deno中写入大型CSV文件的高效实现方案?
提升Deno CSV百万行写入速度的优化方案
你猜的没错——单个yield每条数据会带来频繁的异步迭代开销和磁盘IO调用,这正是写入速度慢的核心原因。批处理是解决这类问题的关键,以下是具体优化思路和代码实现:
核心优化方向
- 批量处理数据块:减少异步迭代的次数,降低库内部的循环开销
- 合并磁盘写入操作:磁盘IO是性能瓶颈,批量写入能大幅减少系统调用次数
- 简化异步流程:避免不必要的异步生成器开销,直接批量生成CSV内容
优化后的代码实现
方案1:批量异步生成器(适配原writeCSVObjects)
如果想继续使用writeCSVObjects,可以修改异步生成器,每次yield一个数据块而非单个对象,同时配合自定义批量写入逻辑:
// generate a really long array to simulate input const data = []; for (let i = 0; i < 1000000; i++) { data.push({plz: '12345', strasse: 'Teststrasse'}); } // 批量异步生成器:每次返回指定大小的数据块 async function* batchAsyncIterator(data: any[], batchSize: number = 1000): AsyncGenerator<any[]> { let batch = []; for (const entry of data) { batch.push(entry); if (batch.length === batchSize) { yield batch; batch = []; } } // 处理剩余不足一个批次的数据 if (batch.length > 0) { yield batch; } } async function writeCSV(data: any[]): Promise<void> { const file = await Deno.open('./test.csv', {write: true, create: true, truncate: true}); const encoder = new TextEncoder(); // 先写入表头 await Deno.writeAll(file, encoder.encode('plz,strasse\n')); const iterator = batchAsyncIterator(data, 2000); for await (const batch of iterator) { // 批量生成CSV行并写入 const csvContent = batch.map(item => `${item.plz},${item.strasse}`).join('\n') + '\n'; await Deno.writeAll(file, encoder.encode(csvContent)); } file.close(); }
方案2:直接批量生成CSV并写入(性能最优)
如果不需要依赖writeCSVObjects的复杂处理,直接用stringify批量生成CSV内容,配合Deno.writeAll批量写入,性能提升最明显:
import { stringify } from "https://deno.land/std/csv/mod.ts"; // generate a really long array to simulate input const data = []; for (let i = 0; i < 1000000; i++) { data.push({plz: '12345', strasse: 'Teststrasse'}); } async function writeCSV(data: any[]): Promise<void> { const file = await Deno.open('./test.csv', {write: true, create: true, truncate: true}); const writer = file.writable.getWriter(); const encoder = new TextEncoder(); // 写入表头 await writer.write(encoder.encode('plz,strasse\n')); const batchSize = 2000; // 可根据内存情况调整,建议1000-5000 for (let i = 0; i < data.length; i += batchSize) { const batch = data.slice(i, i + batchSize); // 批量生成CSV内容(跳过表头,因为已经单独写入) const csvRows = stringify(batch, {header: false}); await writer.write(encoder.encode(csvRows + '\n')); } await writer.close(); file.close(); }
额外优化建议
- 调整批次大小:测试不同的
batchSize(如1000、2000、5000),找到内存占用和写入速度的平衡点 - 避免全量加载数据:如果原始数据来自文件,不要一次性读取到内存,改为边读边批量写入,降低内存消耗
- 使用同步写入(按需):如果不需要异步流程,可改用
Deno.writeFileSync等同步API,减少异步调度开销
内容的提问来源于stack exchange,提问作者ObstFliege
相关产品推荐
相关产品推荐

