You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Deno中写入大型CSV文件的高效实现方案?

提升Deno CSV百万行写入速度的优化方案

你猜的没错——单个yield每条数据会带来频繁的异步迭代开销和磁盘IO调用,这正是写入速度慢的核心原因。批处理是解决这类问题的关键,以下是具体优化思路和代码实现:

核心优化方向

  1. 批量处理数据块:减少异步迭代的次数,降低库内部的循环开销
  2. 合并磁盘写入操作:磁盘IO是性能瓶颈,批量写入能大幅减少系统调用次数
  3. 简化异步流程:避免不必要的异步生成器开销,直接批量生成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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 04:32:37