[c#] 异步写入多个线程的文件c#



2 Answers

我要做的是有单独的工作线程专门用于编写文件的任务。 当你的其他一个线程需要写出一些数据时,它应该调用一个函数来将数据添加到ArrayList(或其他一些容器/类)。 在这个函数中,顶部应该有一个lock语句,以防止同时执行多个线程。 在添加对ArrayList的引用之后,它返回并继续处理它的杂事。 有几种方法可以处理写入线程。 可能最简单的是简单地将它放入一个带有睡眠语句的无限循环中,这样它就不会咀嚼你的cpu。 另一种方法是使用线程原语,并在没有更多数据要写出时进入等待状态。 此方法意味着您必须使用类似ManualResetEvent.Set方法的方法激活线程。

有许多不同的方法可以在.NET中读取和写出文件。 我写了一个基准程序并在我的博客中给出结果:

http://designingefficientsoftware.wordpress.com/2011/03/03/efficient-file-io-from-csharp

如果您需要性能,我建议使用Windows ReadFile和WriteFile方法。 避免使用任何异步方法,因为我的基准测试结果表明使用同步I / O方法可以获得更好的性能。

Bob Bryan MCSD

Question

这是我的情况。 我想在我的应用程序中尽可能高效地写入文件系统。 该应用程序是多线程的,每个线程都可以写入同一个文件。 有没有一种方法可以从每个线程异步写入文件,而不会让不同线程中的写入结合在一起,可以这么说?

我正在使用C#和.NET 3.5,我也安装了Reactive Extensions。




这是一个表单,它启动在同一个txt文件中写入的线程定义的数字。 它已经在.net 3.5和winforms中创建,我认为你可以适应你的使用。 创建一个表单并添加一个按钮! 希望能帮助到你!

public partial class Form1 : Form
{
    private const int NumberThreads = 39; //Total Threads
    private const int NumberLines = 999; // Lines per Thread
    private string _filePath = Path.Combine(Directory.GetCurrentDirectory(), "debug.txt");

    private static readonly object _objectLock = new object();

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (File.Exists(_filePath))
            File.Delete(_filePath); //delete file

        if (!File.Exists(_filePath))
            using (var sw = File.CreateText(_filePath)) //create file
                sw.WriteLine("TEST MULTITHREAD WRITTER"); //write header

        //create threads
        for (var i = 0; i <= NumberThreads; i++)
        {
            var thread = new Thread(ThreadWrite) { IsBackground = true };
            thread.Start(); //start threads
        }
    }

    private void ThreadWrite()
    {
        for (var i = 0; i <= NumberLines; i++)
        {
            //append a date in line
            AppendLine(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss")); 
            //sleeps a rand interval between 1 and 10 secs
            Thread.Sleep(new Random().Next(1, 10));
        }
    }

    private void AppendLine(string text)
    {
        lock (_objectLock)
        {
            var line = text;
            using (var sw = new StreamWriter(_filePath, true))
            {
                //write line to file
                sw.WriteLine(line);
                //close file
                sw.Close();
            }
        }
    }
}



虽然基于线程的锁可以解决这个问题,但是有一种方法可以跨线程工作,但是当您有多个进程写入单个文件的末尾时,最好使用这种方式。

要在进程(或线程)之间获得此行为,请指定在创建OS文件句柄时希望对操作系统进行原子追加写入。 这是通过在Posix(Linux,Unix)下指定O_APPEND,在Windows下指定FILE_APPEND_DATA来完成的。

在C#中,您不直接调用操作系统'open'或'CreateFile'系统调用,但有办法获得此结果。

我问过一段时间以前在Windows下如何做到这一点,并在这里得到了两个好的答案: 如何在C#中进行原子写/附加,或者如何使用FILE_APPEND_DATA标志打开文件?

基本上,您可以使用FileStream()或PInvoke,我建议使用PInvoke上的FileStream(),原因很明显。

除了FileSystemRights.AppendData标志之外,您还可以使用FileStream()的构造函数参数来指定异步文件I / O,该标志应该为您提供异步I / O和原子追加写入文件。

警告:某些操作系统对以这种方式原子写入的最大字节数有限制,超过该阈值将删除操作系统的原子性承诺。

由于这个最后的问题,我建议在尝试在单个进程中解决您的问题时保持lock()样式争用管理。






Related