Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: memcpy в C#  (Прочитано 2829 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« : 13-12-2013 23:31 » 

Вот простая казалось бы вещь: скопировать кусок памяти с одного IntPtr в другой. И вдруг обнаруживается, что ничего такого в C# нет.

Придётся делать своё.

Сначала посмотрим, что вообще в C# имеется:

Копирование массивов по элементам:
Код: (C#)
source.CopyTo(destination, 0);
где source и destination - некоторые массивы. Будем считать его эталонным, с которым сравнивать всё остальное.

Далее, есть копирование массивов как байтовый блок - тот самый memcpy
Код: (C#)
Buffer.BlockCopy(source, 0, destination, 0, size);
Работает аж в 4 раза быстрее, чем предыдущий вариант. Но, увы, ничего не понимает в указателях.

Есть копирование в маршалинге между управляемым и неуправляемым кодом:
Код: (C#)
Marshal.Copy(sourcePointer, destination, 0, size);
Marshal.Copy(source, 0, destinationPointer, size);
Работает почему-то с переменным успехом: скорость "скачет" от максимума - как у Buffer до в два раза медленнее. Т.е. в 2-4 раза быстрее Array.CopyTo. Увы, понимает только один указатель.

Побайтовое копирование вручную:
Код: (C#)
byte* srcPtr = (byte*)sourcePointer.ToPointer(), dstPtr = (byte*)destinationPointer.ToPointer();
for(int i = 0; i < bigSize; ++i, ++srcPtr, ++dstPtr)
{
        *dstPtr = *srcPtr;
}
Работает в 2 раза медленнее, чем Array.CopyTo и в 7 раз медленнее, чем Buffer.BlockCopy. Этим путём мы не пойдём.

Сделать обёртку типа Array над указателем никак - класс не наследуется. Можно только наоборот: получить указатель на массив.

Ничего не остаётся, как комбинировать цикл по указателям с блочными операциями маршалинга.
Код: (C#)
public unsafe static void memcpy(void* dst, void* src, int count)
{
        const int blockSize = 4096;
        byte[] block = new byte[blockSize];
        byte* d = (byte*)dst, s = (byte*)src;
        for(int i = 0, step; i < count; i += step, d += step, s += step)
        {
                step = count - i;
                if(step > blockSize)
                {
                        step = blockSize;
                }
                Marshal.Copy(new IntPtr(s), block, 0, step);
                Marshal.Copy(block, 0, new IntPtr(d), step);
        }
}
Работает в 2 раза быстрее Array.CopyTo, в 2 раза медленнее Buffer.BlockCopy, и стабильно как Marshal.Copy в худшем случае.

Опыты проводились на объёмах в 500 Мб.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines