一個超級大的檔案如何更快讀

2023-06-08 12:00:51

一個超級大的檔案如何更快讀

問題起因

一個有千萬的資料的txt檔案如何發揮IO的全部效能更快的讀和寫。

方案一

使用ChatGPT4的方案

在C#中,我們可以使用多執行緒來處理大量的資料並將其寫入資料庫。在處理巨量資料時,我們需要將任務分解為多個子任務,這樣我們可以在不同的執行緒中並行執行它們以提高效能。

這裡是一種可能的解決方案,使用了Task Parallel Library (TPL)來實現多執行緒。假設我們使用的是SQL Server資料庫,並且我們正在處理的檔案是TSV(Tab-Separated Values)檔案。

using System;
using System.IO;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Collections.Concurrent;

class Program
{
    static void Main()
    {
        string path = "yourFile.tsv";
        ConcurrentQueue<string[]> queue = new ConcurrentQueue<string[]>();

        var producer = Task.Run(() =>
        {
            using (var reader = new StreamReader(path))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    var fields = line.Split('\t');
                    queue.Enqueue(fields);
                }
            }
        });

        var consumers = new Task[4];
        for (int i = 0; i < consumers.Length; i++)
        {
            consumers[i] = Task.Run(() =>
            {
                string connString = "Your connection string";
                using (var conn = new SqlConnection(connString))
                {
                    conn.Open();
                    while (true)
                    {
                        if (queue.TryDequeue(out string[] fields))
                        {
                            using (var cmd = new SqlCommand("Your insert command", conn))
                            {
                                // Update parameters in cmd using fields
                                cmd.ExecuteNonQuery();
                            }
                        }
                        else if (producer.IsCompleted)
                        {
                            break;
                        }
                    }
                }
            });
        }

        Task.WaitAll(consumers);
    }
}

在上面的程式碼中,我們首先建立了一個生產者任務,該任務從TSV檔案中讀取每一行,然後將每一行分割為欄位,並將結果存入佇列。然後我們建立了4個消費者任務,每個消費者任務都從佇列中

題外話題

如果這個檔案是按照行去分割資料如何利用多執行緒去發揮更高效能?

討論 採用偏移值去分多個任務讀,並且需要解決偏移值不一定還在每一行中的位置,使用需要設計好如何解決偏移值的位置問題。

首先規定任務的偏移值提供案例:

[
	{
	"start":0,
	"end":10000
	},
	{
	"start":10001,
	"end":20000
	},
	{
	"start":20001,
	"end":30000
	},
	{
	"start":30000,
	"end":40000
	}
]

在這裡提供了四個任務,每一個任務的偏移值都是固定的,請注意,我們的檔案的資料是按照每個換行符去分割資料,如果使用了偏移值,我們無法保證偏移值的位置一定是每一行的開頭,這個時候需要注意如何處理偏移值的問題,下面我提供一個簡單的解決方法,採用虛擬碼

var data = new object []{
   
	{
	"start":0,
	"end":10000
	},
	{
	"start":10001,
	"end":20000
	},
	{
	"start":20001,
	"end":30000
	},
	{
	"start":30000,
	"end":40000
	}
}

// 處理偏移值的方法

// 提供多個執行緒任務去並行執行讀

通過虛擬碼我們可以看到,解決偏移值的問題是由先提供一個方法,將每一個偏移值去先處理一邊在去執行任務。這樣就可以解決問題。

這個屬於題外話題。如果大佬們有其他想法也可以討論,話題不在意IO的瓶頸,如何更快的讀