А как бы вы написали?
От: Sinix  
Дата: 19.12.09 04:58
Оценка:
Вытащил из http://www.rsdn.ru/forum/philosophy/3644575.1.aspx
Автор: Sinix
Дата: 18.12.09


Есть регулярная задачка "обойти структуру папок и сгенерить аналогичную структру, но с другими данными".
При этом
а) некоторые папки надо пропустить.
б) имена папок/файлов в папке назначения могут различаться и об этом надо знать вызывающему коду.

Как оно выглядит сейчас — см код и пример ниже (убраны проверки, на практике лучше не использовать)
Реальный код — UniversIS.IO.FileSystemHelper.VisitAll() — брать здесь
Автор: Sinix
Дата: 17.12.09
).

Страшно? Так вот, этот код с марта
1) существовал как один метод
2) был вынесен в библиотеку компонентов
3) параметры были объединены в структуру
4) был вынесен в отдельный класс, унаследованный от Component (раздулся втрое и стал вообще неподдерживаемым)
5) приведён к текущему виду и отмечен как // DONTTOUCH. Кстати, такие комментарии в Task List window — великое дело.

Придумаете как это написать красивее?



Злостный оффтоп

Сравнил время копирования (см код ещё ниже)
-кодом со всеми проверками,
-Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(src, dest2),
-Far'a (1,71a3, системные функции копирования)
-проводника win7.

Внимание вопрос:
Из какого места у товарищей растут руки, если мой абсолютно не оптимизированный код на паре тысяч мелких файлов выигрывает от %10 у кода из библиотеки VB и до 150% (30 сек vs 2 мин) у фара???

Не, понятно что без полноценной проверки на разных машинах/с разными наборами никаких выводов быть не должно. Но вопрос "чем оно там занимается" по-прежнему в силе.



Код для "переписать":

    public delegate void DirectoryCallback(
      string source, ref string destination,
      ref bool newDestinationContainer, out bool skipSubitems);

    public delegate void FileCallback(
      string source, ref string destination,
      bool newDestinationContainer);

    public static void VisitAll(
      string source, ref string destination,
      DirectoryCallback directoryCallback, FileCallback fileCallback)
    {
      if (source.EndsWith("\\") || source.EndsWith("/"))
      {
        VisitAllInternal(
          source, ref destination,
          directoryCallback, fileCallback,
          !Directory.Exists(Path.GetDirectoryName(destination)));
      }
      else
      {
        fileCallback(
          source,
          ref destination,
          !Directory.Exists(Path.GetDirectoryName(destination.TrimEnd('\\','/'))));
      }
    }

    private static void VisitAllInternal(
      string source, ref string destination,
      DirectoryCallback directoryCallback, FileCallback fileCallback, bool newDestinationContainer)
    {
      bool skip = false;
      if (directoryCallback != null)
      {
        directoryCallback(source, ref destination, ref newDestinationContainer, out skip);
      }

      if (!skip)
      {
        if (fileCallback != null)
        {
          foreach (string fileName in Directory.GetFiles(source))
          {
            string destFile = destination + fileName.Substring(source.Length);
            fileCallback(fileName, ref destFile, newDestinationContainer);
          }
        }

        foreach (string dir in Directory.GetDirectories(source))
        {
          string sourceDir = dir + "\\";
          string destDir = destination + sourceDir.Substring(source.Length);
          VisitAllInternal(sourceDir, ref destDir, directoryCallback, fileCallback, newDestinationContainer);
        }
      }
    }


Пример использования (хотя для такой простой задачи это оверкилл):
    public static void Copy(string source, string destination)
    {
      VisitAll(source, ref destination,
        delegate(string dir, ref string destDir, ref bool newDestinationContainer, out bool skip)
        {
          if (newDestinationContainer || !Directory.Exists(destDir))
          {
            Directory.CreateDirectory(destDir);
            newDestinationContainer = true;
          }
          skip = false;
        },
        delegate(string file, ref string destFile, bool newDestinationContainer)
        {
          File.Copy(file, destFile, !newDestinationContainer);
        });
    }




Измерение времени копирования:
    public static void Measure(string message, Action callback)
    {
      long mem = GC.GetTotalMemory(true);
      long gcCount = GC.CollectionCount(0);


      DateTime now = DateTime.Now;
      Stopwatch stopwatch = Stopwatch.StartNew();
      callback();
      TimeSpan elapsed = stopwatch.Elapsed;
      TimeSpan elapsedReal = DateTime.Now - now;

      // DONTTOUCH:
      //  It is intended to call GetTotalMemory with forceFullCollection: false
      //  _before_ GC.CollectionCount call.
      BinarySize memDelta = new BinarySize(GC.GetTotalMemory(false) - mem);
      long gcCountDelta = GC.CollectionCount(0) - gcCount;

      Console.WriteLine(
@"-------
{0}:
  Elapsed:      {1}, MemDelta: {2}
  Elapsed real: {3}, GC count: {4}",
        message, elapsed, memDelta, elapsedReal, gcCountDelta);
    }

    [STAThread]
    static void Main(string[] args)
    {
      string src = @"src path";
      string dest = @"dest path";
      string dest2 = @"dest path for vb";

      Console.WriteLine("Start...");

      TestHelper.Measure(
        "FsHelper",
        () => FileSystemHelper.Copy(src, ref dest, FileSystemConflict.GenerateFileNames));

      TestHelper.Measure(
        "VB",
        () => Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(src, dest2));

      TestHelper.Measure(
        "Del FsHelper",
        () => FileSystemHelper.DeleteIfExists(dest));

      TestHelper.Measure(
        "Del Directory (fails on read-only)",
        () => Directory.Delete(dest2));

      Console.WriteLine("Done...");
      Console.ReadKey();
    }
Re: А как бы вы написали?
От: Jolly Roger  
Дата: 19.12.09 07:03
Оценка: 12 (1)
Здравствуйте, Sinix, Вы писали:

S>Внимание вопрос:

S>Из какого места у товарищей растут руки, если мой абсолютно не оптимизированный код на паре тысяч мелких файлов выигрывает от %10 у кода из библиотеки VB и до 150% (30 сек vs 2 мин) у фара???

Боюсь, Ваш тест не вполне корректен. После каждого теста следовало бы перезагружать машину, дабы гарантированно сбросить файловый кэш системы.

S>А как бы вы написали?


Что-нибудь вроде этого

    public interface ICopyControl
    {
        bool CanCopyFile(string source, string dest);
        bool CanCopyDir(string source, string dest);
    }

    class Program
    {
        public static EventWaitHandle completeEvent =
            new EventWaitHandle(false, EventResetMode.AutoReset);
        public static int ItemsCount;

        public static void Copy(
            string sourceDir, string destDir, ICopyControl copyControl)
        {
            try
            {
                if (!Directory.Exists(destDir)) Directory.CreateDirectory(destDir);
                var dirs = Directory.GetDirectories(sourceDir);
                var dest = destDir + "\\";
                for (int i = 0; i < dirs.Length; )
                {
                    var src = dirs[i++];
                    var dst = dest + src.Substring(sourceDir.Length);
                    if (copyControl == null || copyControl.CanCopyDir(src, dst))
                    {
                        Interlocked.Increment(ref ItemsCount);
                        ThreadPool.QueueUserWorkItem((o) =>
                            {
                                Copy(src, dst, copyControl);
                            });
                    }
                }

                var files = Directory.GetFiles(sourceDir);
                for (int i = 0; i < files.Length; )
                {
                    var srcF = files[i++];
                    var dstF = dest + srcF.Substring(sourceDir.Length);
                    if (copyControl == null || copyControl.CanCopyFile(srcF, dstF))
                    {
                        File.Copy(srcF, dstF);
                    }
                }
            }
            finally
            {
                if (Interlocked.Decrement(ref ItemsCount) == 0) completeEvent.Set();
            }
        }

        public static void TestCopy(string sourceDir, string destDir)
        {
            if (!Directory.Exists(sourceDir)) return;
            completeEvent.Reset();
            Thread.VolatileWrite(ref ItemsCount, 1);
            Copy(sourceDir, destDir, null);
            completeEvent.WaitOne();
        }

        static void Main(string[] args)
        {
            TestCopy(@"K:\A1", @"K:\B1");
            Console.WriteLine("Complete");
            Console.ReadKey();
        }
    }
"Нормальные герои всегда идут в обход!"
Re[2]: А как бы вы написали?
От: Sinix  
Дата: 19.12.09 07:38
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Здравствуйте, Sinix, Вы писали:


S>>Внимание вопрос:

S>>Из какого места у товарищей растут руки, если мой абсолютно не оптимизированный код на паре тысяч мелких файлов выигрывает от %10 у кода из библиотеки VB и до 150% (30 сек vs 2 мин) у фара???

JR>Боюсь, Ваш тест не вполне корректен. После каждого теста следовало бы перезагружать машину, дабы гарантированно сбросить файловый кэш системы.


S>>А как бы вы написали?


JR>Что-нибудь вроде этого


JR>
JR>    public interface ICopyControl
JR>    {
JR>        bool CanCopyFile(string source, string dest);
JR>        bool CanCopyDir(string source, string dest);
JR>    }

JR>    class Program
JR>    {
JR>        public static EventWaitHandle completeEvent =
JR>            new EventWaitHandle(false, EventResetMode.AutoReset);
JR>        public static int ItemsCount;

JR>        public static void Copy(
JR>            string sourceDir, string destDir, ICopyControl copyControl)
JR>        {
JR>            try
JR>            {
JR>                if (!Directory.Exists(destDir)) Directory.CreateDirectory(destDir);
JR>                var dirs = Directory.GetDirectories(sourceDir);
JR>                var dest = destDir + "\\";
JR>                for (int i = 0; i < dirs.Length; )
JR>                {
JR>                    var src = dirs[i++];
JR>                    var dst = dest + src.Substring(sourceDir.Length);
JR>                    if (copyControl == null || copyControl.CanCopyDir(src, dst))
JR>                    {
JR>                        Interlocked.Increment(ref ItemsCount);
JR>                        ThreadPool.QueueUserWorkItem((o) =>
JR>                            {
JR>                                Copy(src, dst, copyControl);
JR>                            });
JR>                    }
JR>                }

JR>                var files = Directory.GetFiles(sourceDir);
JR>                for (int i = 0; i < files.Length; )
JR>                {
JR>                    var srcF = files[i++];
JR>                    var dstF = dest + srcF.Substring(sourceDir.Length);
JR>                    if (copyControl == null || copyControl.CanCopyFile(srcF, dstF))
JR>                    {
JR>                        File.Copy(srcF, dstF);
JR>                    }
JR>                }
JR>            }
JR>            finally
JR>            {
JR>                if (Interlocked.Decrement(ref ItemsCount) == 0) completeEvent.Set();
JR>            }
JR>        }

JR>        public static void TestCopy(string sourceDir, string destDir)
JR>        {
JR>            if (!Directory.Exists(sourceDir)) return;
JR>            completeEvent.Reset();
JR>            Thread.VolatileWrite(ref ItemsCount, 1);
JR>            Copy(sourceDir, destDir, null);
JR>            completeEvent.WaitOne();
JR>        }

JR>        static void Main(string[] args)
JR>        {
JR>            TestCopy(@"K:\A1", @"K:\B1");
JR>            Console.WriteLine("Complete");
JR>            Console.ReadKey();
JR>        }
JR>    }
JR>
Re[3]: А как бы вы написали?
От: Jolly Roger  
Дата: 19.12.09 08:19
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Jolly Roger, Вы писали:


Это из какого смысла Я имею в виду, что уже не в первый раз вижу копирование чьего-то поста без комментариев, может за этим скрывается какой-то особый посыл, а я просто не в курсе этой здешней традиции? А хотелось бы
"Нормальные герои всегда идут в обход!"
Re: А как бы вы написали?
От: Воронков Василий Россия  
Дата: 19.12.09 09:21
Оценка:
Здравствуйте, Sinix, Вы писали:

А попробуй тест в обратном порядке запустить — сначала твой код, потом бейсик, потом фар. Что получится?
Re[4]: А как бы вы написали?
От: Sinix  
Дата: 19.12.09 09:46
Оценка: 10 (1)
Здравствуйте, Jolly Roger, Вы писали:

Это не мода, это глюки.

Коротко:
1) Спасибо
2) Согласен, обобщать неправомерно. Тем не менее, запускал несколько раз в различном порядке
3) Многопоточность — не самая лучшая идея для копирования, особенно для больших файлов.
Специальный дохлокомп для тестирования (cel 2.4/512 mb/win7 забитый чем только можно):
Size: 83,1 Mb (87 182 492b)
Files: 2 527, Directories: 1 012
-------
VB:
  Elapsed:      00:01:43.2115405, MemDelta: 505,398 KB
  Elapsed real: 00:01:43.2070880, GC count: 329
-------
Jolly Roger's:
  Elapsed:      00:01:50.1099564, MemDelta: 345,836 KB
  Elapsed real: 00:01:50.1057904, GC count: 67
-------
FsHelper:
  Elapsed:      00:01:00.2282175, MemDelta: 115,73 KB
  Elapsed real: 00:01:00.2327816, GC count: 75

4) Async file IO может дать ещё чуть чуть выигрыша, а может и не дать.
5) Пример с копированием был, как ни странно, примером. Речь шла об обходе папок (с возможностью пропуска отдельных веток), формированием destination path и скармливании обработчикам для директорий/файлов.
Re[2]: А как бы вы написали?
От: Sinix  
Дата: 19.12.09 09:53
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>А попробуй тест в обратном порядке запустить — сначала твой код, потом бейсик, потом фар. Что получится?


Примерно то же самое. Правда far изредка отрабатывает всего на 20% медленнее.

Что характерно, весь код использует WinApi, и причина явно не в кривизне винды.

Оффтоп 2:
managed жрёт память грите? Память — рабочий набор:
Live Writer (.NET)- 25 mb ,
Студия — 104 mb,
Opera — 370 mb (13 вкладок, картинки/флеш отключены).

Чтоп я так жил...
Re[5]: А как бы вы написали?
От: Jolly Roger  
Дата: 19.12.09 10:46
Оценка:
Здравствуйте, Sinix, Вы писали:

S>3) Многопоточность — не самая лучшая идея для копирования, особенно для больших файлов.


Ну так Вы же на целероне запускали Согласитесь, сейчас имеет прямой смысл ориентироваться на более продвинутые архитектуры. Кроме многоядерности сейчас уже не редкость и RAID-ы даже на десктопах.

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

Всё равно это мелочи, за реальным ускорением надо в натив идти, в недокументированное API, некоторые даже в ядро лезут, и надо признать — там реальные приросты получают, но я не сторонник столь глубокого бурения для прикладных задач
"Нормальные герои всегда идут в обход!"
Re: А как бы вы написали?
От: Lloyd Россия  
Дата: 19.12.09 11:32
Оценка: 13 (2) +2
Здравствуйте, Sinix, Вы писали:

S>Придумаете как это написать красивее?


"Красиво" — понятие растяжимое. Лично я постарался бы вынести функциоал обхода дерева:
public static class TreeTraverser
{
    public static void Traverse<T>(T root, Func<T, IEnumerable<T>> getChildren, Action<T> visitor)
    {
        visitor(root);
        foreach (T child in getChildren(root) ?? Enumerable.Empty<T>())
        {
            Traverse(child, getChildren, visitor);
        }
    }
}


Тогда функция копирования структуры папок выглядела бы вот так:
var intialState = new
{
    dir = true,
    src = "c:\\Download",
    dst = "c:\\Tmp\\Test"
};
TreeTraverser.Traverse(
    intialState,
    state =>
    {
        if (!state.dir)
            return null;
        var dirs = from d in Directory.GetDirectories(state.src)
                   let folderName = Path.GetFileName(d)
                   select new
                   {
                       dir = true,
                       src = d,
                       dst = Path.Combine(state.dst, folderName)
                   };
        var files = from d in Directory.GetFiles(state.src)
                    let folderName = Path.GetFileName(d)
                    select new
                    {
                        dir = false,
                        src = d,
                        dst = Path.Combine(state.dst, folderName)
                    };
        return dirs.Concat(files);
    },
    state =>
    {
        if (state.dir && !Directory.Exists(state.dst))
            Directory.CreateDirectory(state.dst);
    }
);
Re[6]: А как бы вы написали?
От: Lloyd Россия  
Дата: 19.12.09 11:42
Оценка: +1
Здравствуйте, Jolly Roger, Вы писали:

S>>3) Многопоточность — не самая лучшая идея для копирования, особенно для больших файлов.


JR>Ну так Вы же на целероне запускали Согласитесь, сейчас имеет прямой смысл ориентироваться на более продвинутые архитектуры. Кроме многоядерности сейчас уже не редкость и RAID-ы даже на десктопах.


Мне кажется, вы не до конца поняли суть комментария. Наличие хоть сотни ядер у процессора не сильно поможет в задаче ускорения копирования файлов. Более того, использование многопоточности в данном случае может привести к багам. ThreadPool по-моему никак не гарантирует упорядоченности выполнения задач, и ледовательно вполне можно столкнуться с ситуацией, когда код копирования файла запускается раньше кода создания каталога для этого файла.

JR>Асинхронность может дать прирост, но с ней возни много для получения реального выигрыша, а я этот пример прямо сейчас набросал и не тестировал, только один раз запустил, чтобы убедиться в работоспособности Поначалу и хотел организовать копирование асинхронно, но потом поленился


Асинхронность может дать заметный выигрыш если у вас код обращается к разным независимым ресурсам. В этом примере ресурс один — контроллер диска. Приросту взяться особо не откуда.
Re[7]: А как бы вы написали?
От: Jolly Roger  
Дата: 19.12.09 12:34
Оценка: +1
Здравствуйте, Lloyd, Вы писали:

L>Мне кажется, вы не до конца поняли суть комментария. Наличие хоть сотни ядер у процессора не сильно поможет в задаче ускорения копирования файлов. Более того, использование многопоточности в данном случае может привести к багам. ThreadPool по-моему никак не гарантирует упорядоченности выполнения задач, и ледовательно вполне можно столкнуться с ситуацией, когда код копирования файла запускается раньше кода создания каталога для этого файла.


JR>>Асинхронность может дать прирост, но с ней возни много для получения реального выигрыша, а я этот пример прямо сейчас набросал и не тестировал, только один раз запустил, чтобы убедиться в работоспособности Поначалу и хотел организовать копирование асинхронно, но потом поленился


L>Асинхронность может дать заметный выигрыш если у вас код обращается к разным независимым ресурсам. В этом примере ресурс один — контроллер диска. Приросту взяться особо не откуда.


ThreadPool не гарантирует, но здесь директория создаётся до того, как в неё начинают копироваться файлы, поэтому переупорядочивание запросов пулом повлиять никак не может. По поводу одного ресурса и влияния асинхронности, то вопрос не столь прост. Контроллер может быть и не один, если копируем с одного физического диска на другой. Это может быть контроллер RAID-массива, а они бывают разные. Современные SATA контроллеры способны перупорядочивать выданные им запросы с целью оптимизации обращений к дискам, но для этого они должны иметь сразу несколько запросов, чего не добиться в однопоточной работающей синхронно программе. Во всяком случае, в стандарт SATA такая возможность заложена. Копирование — по большей части физическая работа с диском, но не только, кое-что приходится делать и процессору. Но при синхронной работе процессор будет просто стоять, пока выполняется обращение к диску. Тем более это актуально, когда идёт не только копирование, но и промежуточная переработка данных. Имея два потока на ядро мы уже в определённой степени можем совместить эти операции, асинхрон будет ещё более эффективен.

То есть если стоит задача получить максимум скорости, то надо собирать информацию о системе и выбирать алгоритм, исходя из имеющихся ресурсов, а это геморрно, и результат не столь впечатляющ, чтобы стоило на это тратиться.
"Нормальные герои всегда идут в обход!"
Re[8]: А как бы вы написали?
От: Lloyd Россия  
Дата: 19.12.09 15:25
Оценка: +1
Здравствуйте, Jolly Roger, Вы писали:

L>>Асинхронность может дать заметный выигрыш если у вас код обращается к разным независимым ресурсам. В этом примере ресурс один — контроллер диска. Приросту взяться особо не откуда.


JR>ThreadPool не гарантирует, но здесь директория создаётся до того, как в неё начинают копироваться файлы, поэтому переупорядочивание запросов пулом повлиять никак не может.


+1. Это я проглядел.

JR>По поводу одного ресурса и влияния асинхронности, то вопрос не столь прост. Контроллер может быть и не один, если копируем с одного физического диска на другой. Это может быть контроллер RAID-массива, а они бывают разные. Современные SATA контроллеры способны перупорядочивать выданные им запросы с целью оптимизации обращений к дискам, но для этого они должны иметь сразу несколько запросов, чего не добиться в однопоточной работающей синхронно программе. Во всяком случае, в стандарт SATA такая возможность заложена.


Для нового файла? Если честно, не могу представить зачем может понадобиться такое переупорядочивание для "нового" файла.

JR>Копирование — по большей части физическая работа с диском, но не только, кое-что приходится делать и процессору. Но при синхронной работе процессор будет просто стоять, пока выполняется обращение к диску. Тем более это актуально, когда идёт не только копирование, но и промежуточная переработка данных. Имея два потока на ядро мы уже в определённой степени можем совместить эти операции, асинхрон будет ещё более эффективен.


Это копейки.
Re: А как бы вы написали?
От: Константин Л. Франция  
Дата: 21.12.09 00:08
Оценка:
Здравствуйте, Sinix, Вы писали:

[]

afaik, far использует net file api, который почему-то иногда тормозит. как пример — часто пустая папка или файл удаляются минутами (sic!)
Re[6]: А как бы вы написали?
От: Sinix  
Дата: 21.12.09 01:02
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Ну так Вы же на целероне запускали Согласитесь, сейчас имеет прямой смысл ориентироваться на более продвинутые архитектуры. Кроме многоядерности сейчас уже не редкость и RAID-ы даже на десктопах.


1) вам уже ответил Lloyd.

JR>Всё равно это мелочи, за реальным ускорением надо в натив идти, в недокументированное API, некоторые даже в ядро лезут, и надо признать — там реальные приросты получают, но я не сторонник столь глубокого бурения для прикладных задач


Речь шла совсем не об этом — вопрос был в том, почему код, для производительности и не заточенный, работает слегка шустрее специализированных программ?
Re[2]: А как бы вы написали?
От: Sinix  
Дата: 21.12.09 01:09
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>"Красиво" — понятие растяжимое. Лично я постарался бы вынести функциоал обхода дерева:


Ага, получается вполне удобно. Блин! Я примерно так же выносил состояние в похожей ситуации — в парсере файловых путей... пожалуй, так и сделаю.

Спасибо!
Re[2]: А как бы вы написали?
От: Sinix  
Дата: 21.12.09 01:49
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>"Красиво" — понятие растяжимое. Лично я постарался бы вынести функциоал обхода дерева:

Мдя... получается то же самое — callbacks в VisitAll не должны заниматься получением папок/файлов — это должно быть сделано за них. Ваш вариант упрощает сам метод VisitAll — грабли с передачей параметров в делегаты остаётся. Либо оставить как есть, либо всё-таки сгруппировать параметры в что-то типа VisitState. По второму кругу?

P.S. А не намекают ли такие грабли на необходимость пересмотреть подход? Не хотелось бы — в остальном всё прямо замечательно.
Re: А как бы вы написали?
От: Uzzy Россия  
Дата: 21.12.09 08:24
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Сравнил время копирования (см код ещё ниже)

S>-кодом со всеми проверками,
S>-Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(src, dest2),
S>-Far'a (1,71a3, системные функции копирования)
S>-проводника win7.

S>Внимание вопрос:

S>Из какого места у товарищей растут руки, если мой абсолютно не оптимизированный код на паре тысяч мелких файлов выигрывает от %10 у кода из библиотеки VB и до 150% (30 сек vs 2 мин) у фара???

Ваш вариант включает обновление ГУИ?
Re[2]: А как бы вы написали?
От: Sinix  
Дата: 21.12.09 08:53
Оценка:
Здравствуйте, Uzzy, Вы писали:

U>Ваш вариант включает обновление ГУИ?


Похоже, проблема была не в нём — даже на полудохлой машинке проц не доходил до 100, узкое место — очередь диска (0,7..5,0). Уже предположили что проблема была в неэффективном коде фара'а — тот использует net file api.

Не спорю, может консольный фар интенсивно свопится, но при более-менее прямых руках влияние UI на собственно копирование не даёт четырёхкратного замедления.
Re[3]: А как бы вы написали?
От: Lloyd Россия  
Дата: 21.12.09 09:14
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Ваш вариант упрощает сам метод VisitAll — грабли с передачей параметров в делегаты остаётся.


А зачем в них передавать параметры? Задача какая?

S>Либо оставить как есть, либо всё-таки сгруппировать параметры в что-то типа VisitState. По второму кругу?


Может локальных переменных окажется достаточно?
Re[4]: А как бы вы написали?
От: Sinix  
Дата: 21.12.09 09:32
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>А зачем в них передавать параметры? Задача какая?


Попробую описать
1) на диске валяется директория с кучей поддиректорий и папок, организованным хитрым образом.
2) Из исходного набора данных надо сделать похожую, при этом:
2.1) Примитивную логику типа обхода директорий/генерации конечных имён должен выполнять helper.
2.2) логика обработки может изменять имена части конечных папок (допустим было folder стало folder [2009-12-21])
2.2) логика обработки может пропускать некоторые папки (вместе с подпапками), при этом логика пропуска тесно связана с логикой генерации имён — разносить её нежелательно.
3) если изменился корневой путь к директории назначения, то об этом должен узнавать вызывающий код.
4) на практике оказалось, что вызывающий код не унаследован от общего класса — либо инкапсулиуем хелпер, либо используем static-методы (последнее желательней, т.к. меньше проблем с состоянием).

Текущий вариант устраивает всем кроме избыточности параметров и наличия ref-параметров.
Поскольку код инфраструктурный — некритично. Но раздражает
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.