Что самый эффективный путь состоит в том, чтобы упорядочить структуры C++ к C#?

package.yaml фактически обрабатывается hpack ; это не функция stack , за исключением того, что если она увидит ее в вашем проекте, она будет использовать ее и сгенерирует файл .cabal .

Вы можете создать package.yaml самостоятельно с нуля. Вам не нужно делать stack new или что-то еще.

Я, конечно, нахожу это удобным, используя package.yaml , а не project.cabal . Там нет хорошего руководства пользователя, как такового (как указано в hpack README ), но есть несколько примеров, и вы поймете, что там не так уж много:

Я видел несколько упоминаний о том, что библиотека Cabal теперь поддерживает новые функции для уменьшения утомительного повторение (возможно, в формате >= 2.x?), которое может сделать необходимость в package.yaml , исчезнет довольно скоро, что было бы хорошо.

6
задан JaredPar 18 May 2009 в 14:45
поделиться

5 ответов

Для вашего конкретного приложения только одно даст вам окончательный ответ: профилируйте его.

Это уроки, которые я извлек при работе с большими решениями PInvoke. Самый эффективный способ упорядочить данные - это упорядочить непреобразуемые поля. Это означает, что CLR может просто делать то, что составляет memcpy для перемещения данных между собственным и управляемым кодом. Проще говоря, извлеките из своих структур все невстроенные массивы и строки. Если они присутствуют в собственной структуре, представьте их с помощью IntPtr и маршалируйте значения по запросу в управляемый код.

Я никогда не описывал разницу между использованием Marshal.PtrToStructure и разыменованием значения через собственный API. Это, вероятно, то, во что вам следует инвестировать, если PtrToStructure будет обнаружен как узкое место в результате профилирования.

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

6
ответ дан 8 December 2019 в 13:02
поделиться

Использование Marshal.PtrToStructure работает довольно медленно. Я нашел следующую статью о CodeProject, в которой очень полезно сравнивать (и тестировать) различные способы чтения двоичных данных:

Быстрое чтение двоичных файлов с помощью C #

8
ответ дан 8 December 2019 в 13:02
поделиться

В дополнение к исчерпывающему ответу JaredPar вам не нужно использовать GCHandle , вместо этого вы можете использовать небезопасный код.

fixed(byte *pBuffer = buffer) {
     record = *((CPP_STRUCT_DEF *)pBuffer);
}  

Вся цель Оператор GCHandle / fixed предназначен для закрепления / исправления определенного сегмента памяти, делая память неподвижной с точки зрения GC. Если бы память была подвижной, любое перемещение сделало бы ваши указатели недействительными.

Хотя не уверен, какой путь быстрее.

3
ответ дан 8 December 2019 в 13:02
поделиться

Это может выходить за рамки вашего вопроса, но я был бы склонен написать небольшую сборку на управляемом C ++, которая сделала бы fread ( ) или что-то подобное быстро, чтобы прочитать в структурах. После того, как вы прочитали их, вы можете использовать C #, чтобы делать с ними все, что вам нужно.

1
ответ дан 8 December 2019 в 13:02
поделиться

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

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

namespace PersonalUse.IO {

    public sealed class RecordReader<T> : IDisposable, IEnumerable<T> where T : new() {

        const int DEFAULT_STREAM_BUFFER_SIZE = 2 << 16; // default stream buffer (64k)
        const int DEFAULT_RECORD_BUFFER_SIZE = 100; // default record buffer (100 records)

        readonly long _fileSize; // size of the underlying file
        readonly int _recordSize; // size of the record structure
        byte[] _buffer; // the buffer itself, [record buffer size] * _recordSize
        FileStream _fs;

        T[] _structBuffer;
        GCHandle _h; // handle/pinned pointer to _structBuffer 

        int _recordsInBuffer; // how many records are in the buffer
        int _bufferIndex; // the index of the current record in the buffer
        long _recordPosition; // position of the record in the file

        /// <overloads>Initializes a new instance of the <see cref="RecordReader{T}"/> class.</overloads>
        /// <summary>
        /// Initializes a new instance of the <see cref="RecordReader{T}"/> class.
        /// </summary>
        /// <param name="filename">filename to be read</param>
        public RecordReader(string filename) : this(filename, DEFAULT_STREAM_BUFFER_SIZE, DEFAULT_RECORD_BUFFER_SIZE) { }

        /// <summary>
        /// Initializes a new instance of the <see cref="RecordReader{T}"/> class.
        /// </summary>
        /// <param name="filename">filename to be read</param>
        /// <param name="streamBufferSize">buffer size for the underlying <see cref="FileStream"/>, in bytes.</param>
        public RecordReader(string filename, int streamBufferSize) : this(filename, streamBufferSize, DEFAULT_RECORD_BUFFER_SIZE) { }

        /// <summary>
        /// Initializes a new instance of the <see cref="RecordReader{T}"/> class.
        /// </summary>
        /// <param name="filename">filename to be read</param>
        /// <param name="streamBufferSize">buffer size for the underlying <see cref="FileStream"/>, in bytes.</param>
        /// <param name="recordBufferSize">size of record buffer, in records.</param>
        public RecordReader(string filename, int streamBufferSize, int recordBufferSize) {
            _fileSize = new FileInfo(filename).Length;
            _recordSize = Marshal.SizeOf(typeof(T));
            _buffer = new byte[recordBufferSize * _recordSize];
            _fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None, streamBufferSize, FileOptions.SequentialScan);

            _structBuffer = new T[recordBufferSize];
            _h = GCHandle.Alloc(_structBuffer, GCHandleType.Pinned);

            FillBuffer();
        }

        // fill the buffer, reset position
        void FillBuffer() {
            int bytes = _fs.Read(_buffer, 0, _buffer.Length);
            Marshal.Copy(_buffer, 0, _h.AddrOfPinnedObject(), _buffer.Length);
            _recordsInBuffer = bytes / _recordSize;
            _bufferIndex = 0;
        }

        /// <summary>
        /// Read a record
        /// </summary>
        /// <returns>a record of type T</returns>
        public T Read() {
            if(_recordsInBuffer == 0)
                return new T(); //EOF
            if(_bufferIndex < _recordsInBuffer) {
                // update positional info
                _recordPosition++;
                return _structBuffer[_bufferIndex++];
            } else {
                // refill the buffer
                FillBuffer();
                return Read();
            }
        }

        /// <summary>
        /// Advances the record position without reading.
        /// </summary>
        public void Next() {
            if(_recordsInBuffer == 0)
                return; // EOF
            else if(_bufferIndex < _recordsInBuffer) {
                _bufferIndex++;
                _recordPosition++;
            } else {
                FillBuffer();
                Next();
            }
        }

        public long FileSize {
            get { return _fileSize; }
        }

        public long FilePosition {
            get { return _recordSize * _recordPosition; }
        }

        public long RecordSize {
            get { return _recordSize; }
        }

        public long RecordPosition {
            get { return _recordPosition; }
        }

        public bool EOF {
            get { return _recordsInBuffer == 0; }
        }

        public void Close() {
            Dispose(true);
        }

        void Dispose(bool disposing) {
            try {
                if(disposing && _fs != null) {
                    _fs.Close();
                }
            } finally {
                if(_fs != null) {
                    _fs = null;
                    _buffer = null;
                    _recordPosition = 0;
                    _bufferIndex = 0;
                    _recordsInBuffer = 0;
                }
                if(_h.IsAllocated) {
                    _h.Free();
                    _structBuffer = null;
                }
            }
        }

        #region IDisposable Members

        public void Dispose() {
            Dispose(true);
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator() {
            while(_recordsInBuffer != 0) {
                yield return Read();
            }
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        #endregion

    } // end class

} // end namespace

для использования:

using(RecordReader<CPP_STRUCT_DEF> reader = new RecordReader<CPP_STRUCT_DEF>(path)) {
    foreach(CPP_STRUCT_DEF record in reader) {
        // do stuff
    }
}

(здесь довольно новый, надеюсь, что это не так слишком много, чтобы опубликовать ... просто вставил в класс, не вырезал комментарии или что-то еще, чтобы его сократить.)

0
ответ дан 8 December 2019 в 13:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: