Каков наилучший способ размещения следующего:
Приложение, критически важное для производительности в режиме реального времени, которое взаимодействует с собственным Cll для связи с проприетарным бэкэндом.
В нативном API есть сотни и сотни структур, вложенных структур и методов, которые передают данные туда и обратно через эти структуры.
Хотите использовать c # для логики, поэтому остановились на небезопасном c # в пользу cli и marshaling. Я знаю, как и реализовал это через позже, поэтому, пожалуйста, не отвечайте «используйте cli». Маршалинг сотен структур сотню раз в секунду вносит достаточно существенную задержку, что оправдывает расследование небезопасного c #.
Большинство структур c содержит десятки полей, поэтому ищите метод, который бы выполнял минимальную типизацию для каждого из них. На этом этапе все сводится к запуску макроса VS для преобразования каждого строкового элемента в c # эквивалентные установочные массивы в фиксированный размер при необходимости. Это работает довольно хорошо, пока я не попал во вложенный массив struct. Так, например, у меня есть эти 2 структуры:
[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe struct User{
int id;
fixed char name[12];
}
[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe structs UserGroup{
fixed char name[12];
fixed User users[512]
int somethingElse;
fixed char anotherThing[16]
}
Каков наилучший способ размещения постоянных пользователей [512], чтобы не делать много во время выполнения?
Я видел примеры, когда предложение сделать
[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe structs UserGroup{
fixed char name[12];
User users_1;
User users_2;
...
User users_511;
int somethingElse;
fixed char anotherThing[16]
}
Другая идея заключалась в том, чтобы вычислить размер пользователя в байтах и просто сделать это
[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe structs UserGroup{
fixed char name[12];
fixed byte Users[28*512];
int somethingElse;
fixed char anotherThing[16]
}
Но это будет означать, что мне придется делать особую обработку для этой структуры каждый раз, когда мне понадобится ее использовать, или обернуть ее каким-нибудь другим кодом. В API достаточно тех, что я хотел бы избежать такого подхода, но если кто-то может продемонстрировать элегантный способ, которым я мог бы работать
Третий подход, который ускользает от меня настолько, что я не могу произвести и привести пример (я думаю, что где-то видел, но больше не могу его найти) — это указать размер для пользователя или каким-то образом сделать его строго определенным, чтобы вы могли использовать ключевое слово «fixed» в теме.
Кто-нибудь может порекомендовать разумный подход, который они использовали и хорошо масштабируется под нагрузкой?
Лучший способ найти вложенную структуру в небезопасных структурах — это определить их как фиксированные байтовые массивы, а затем предоставить свойство преобразования времени выполнения для поля. Например:
[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe struct UserGroup{
fixed char name[12];
fixed User users[512]
int somethingElse;
fixed char anotherThing[16]
}
Превращается в:
[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe struct UserGroup{
fixed char name[12];
fixed byte users[512 * Constants.SizeOfUser]
int somethingElse;
fixed char anotherThing[16];
public User[] Users
{
get
{
var retArr = new User[512];
fixed(User* retArrRef = retArr){
fixed(byte* usersFixed = users){
{
Memory.Copy(usersFixed, retArrRef, 512 * Constants.SizeOfUser);
}
}
}
return retArr;
}
}
}
Обратите внимание, этот код использует функцию Memory.Copy, представленную здесь: http://msdn.microsoft.com/en-us/library/aa664786(v=vs.71).aspx
Общее объяснение гетера следующее:
Причина, по которой управляемый массив не сохраняется обратно в саму структуру, заключается в том, что он изменяет свою компоновку и больше не будет корректно переводиться, в то время как реквизит не представляет проблемы при получении его от неуправляемого. В качестве альтернативы это может быть включено в другой управляемый объект, который выполняет сохранение.
Других решений пока нет …