Скопировать файл в несколько потоков в .net 3.5

126
14 августа 2019, 15:30

Возможно ли скопировать файл в несколько потоков? Если да, то как? Я пытаюсь сделать что-то подобное, но оно ожидаемо не работает:

using System;
using System.IO;
using System.IO.Compression;
using System.Threading;
namespace MyProgramm
{
    class Copymaker
    {
        private int v_buffer_size;
        FileStream input;
        FileStream output;
        public Thread thread1;
        public Thread thread2;

        public Copymaker(int buffer_size)
        {
            this.v_buffer_size = buffer_size;
        }
        public void Copy(FileInfo fileToCopy)
        {
            using (FileStream originalFileStream = fileToCopy.OpenRead())
            {
                using (FileStream copiedFileStream = File.Create(fileToCompress.FullName + ".new"))
                {
                    input = originalFileStream;
                    output = copiedFileStream;
                    thread1 = new Thread(CopyBuffer);
                    thread1.Start();
                }
                Console.WriteLine("End?");
            }
        }
        private void CopyBuffer()
        {
            byte[] buffer = new byte[v_buffer_size];
            int bytesRead;
            while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, bytesRead);
            }
        }
    }
}

В таком виде, конечно, не работает. Даже поток не запускается (говорит, нет доступа к закрытому потоку). Что я понимаю не верно?

Answer 1

Возможно ли скопировать файл в несколько потоков? Если да, то как?

Возможно. Например, именно так и делает Utorrent. Он сначала резервирует область памяти на винчестере а потом в куче потоков скачивает его из интернета когда это становится возможным (когда на раздаче кто-то появляется) и потом на определенную область зарезервированной памяти вносит изменения в виде бинарного кода с этой же области у оригинального файла из интернета.

А теперь перейдем к НЕЗАДАННОМУ вопросу: Имеет ли это смысл?

Распараллеливание дает прирост скорости исключительно на работе с CPU/GPU. Т.к. поток имеет свои ограничения, но незадействованного ресурса у CPU/GPU еще достаточно.

Но копирование, это работа с HDD. Работа с HDD не станет быстрее если копировать файл в несколько потоков. Она станет МЕДЛЕННЕЕ.

Почему?

Да потому, что HDD работает на основе физики и ты упрешься в возможности механики винчестера. Там есть читающая головка и есть "блин" который крутится с некоей скоростью. Именно по этому у HDD самая высокая скорость записи или чтения -- последовательная. То есть если на блине записаны данные последовательно -- чтение будет быстрым(относительно рандомно размещенных данных). Если нет -- головку нужно перемещать из одной позиции на другую. Распараллеливание задачи копирования сделает так, что головку нужно будет перемещать чаще(логично, не так ли?).

В случае с SSD ты не получишь замедления копирования. Но так же и прироста не получишь. Там нету механики, а это дает высокую скорость чтения/записи рандомно размещенных данных. Зато все равно есть ограничение по скорости. То есть точно так же... Ты хоть последовательно копируй данные, хоть параллельно -- ты получишь идентичную скорость.

А что если копировать через сеть? Например через Ethernet-кабель, получим ли мы желаемый профит? Снова таки нет. Мы упремся в ограничения скорости кабеля. Как упирались в скорость SSD.

А теперь когда мы выяснили что это возможно, но бессмысленно....

Стоит ли решать данную задачу тобой или кем-либо в принципе?)

  1. Резервируешь место под будущий файл нужного размера https://stackoverflow.com/questions/8416413/create-new-file-with-specific-size

  2. Создаешь метод для считывания: адрес файла, начальный байт, конечный байт. Ну или читалку которая считывает с оффсетом. Например такую: https://stackoverflow.com/questions/5208592/reading-parts-of-large-files-from-drive

  3. Метод для обработки данных (что там тебе нужно с ними сделать я не знаю, но ты писал что это не просто копирование). Стоит учесть что я не знаю изменяется ли количество данных или нет, если изменяется хотя бы на один байт -- это стоит учитывать при записи в конечный файл.

  4. метод для записи в конечный файл (адрес файла, начальный байт). https://stackoverflow.com/questions/9529313/write-byte-array-to-middle-of-an-existing-file-in-c-net

  5. Вызываешь нужное количество потоков с вызовом этих методов. Можно попробовать как через таски так и через трэды.

Answer 2

Возможно ли скопировать файл в несколько потоков? Если да, то как?

Не вижу смысла в нескольких потоках на запись. Пусть даже вы и параллельно делаете какую-то работу, но пишущий поток должен быть только 1. Исключение, если вы пишите на разные физические диски.

Реализуйте логику через паттерн Производитель/Потребитель, где производитель- это множество вычислительных потоков, которые результаты своей работы ставят в какую-то потокобезопасную очередь, а потом потребитель- это пишущий поток, который поочередно извлекает блоки данных и пишет их на диск.

READ ALSO
Здесь работает, здесь - нет [закрыт]

Здесь работает, здесь - нет [закрыт]

Программа, написанная на С# 2013 Express, прекрасно работает на моем ПК (W 81) и у заказчика (W 7)

97
Проблема с ennie/ami, laravel

Проблема с ennie/ami, laravel

Есть пакет для работы с астериском под laravel - https://githubcom/enniel/ami Никак не получается настроить

113
Как спарсить ячейки при условии

Как спарсить ячейки при условии

Подскажите пожалуйста как указать границу регулярками в phpНеобходимо спарсить 12 ячеек начиная со слова bet365

97
Не могу сделать curl запрос

Не могу сделать curl запрос

Использую такой запрос :

124