Здравствуйте, AndrewVK, Вы писали:
AVK>Зачем обертывать чужой парсер, если есть родной?
Я же сказал. Если дело в XMLReader... Не факт что он действительно работает быстро. Это нужно проверять.
AVK>Результат очень хороший. Не забывай что это xml.
Блин, твой необоснованный оптимизм просто поражает. Посмотри на результат Трентора. Он между прочем просто текст писал. Если в его код вставить теги и именами олей, то будет тот же эффект, что и с XMLWriter. С загрузкой то же фигня.
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, AndrewVK, Вы писали:
AVK>Влад, но ведь форматтеры выполняют куда больше работы и они куда универсальнее. Просто по моему вместо того чтобы сделать нормальные сериализаторы они предлагают пользоваться форматтерами.
Понятно, что универсальнее. Вот только мне почему-то не хочется платить десятикратными тормозами за эту универсальность. Особенно если речь идет о передачи данных по сети. Где мне полностью плевать на версии, а нужна масимальная скорость.
Всю эту универсальность можно было бы реализовать и без таких страшных провалов производительности. Все что нужно было сделать — это генерировать код сериализации помпилятором, а возможно просто более качественно написать код сериализации. Дтя того же датасета ведь сереализация написана вручную. Но почему-то только в хмл, и почему то тормоза такие же как при использовании SOAP-форматера.
AVK>VDТакой же эффект происходит при некоторый перестановках тестов. Причем на другие способы перестановки влияют незначительно. Что-то там не так.
AVK>Ну так исходники есть.
И что толку с них?
AVK>IT вроде ротор собрал — можно попросить его прогнать форматтер профайлером и посмотреть где кака.
У меня нет нормального профайлера. Если есть что на примете, подкинь...
А вообще, сделать это точно надо. Мне уже просто интересно, что они там такое натварили.
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Сериализация в дотнете 2 - самопальный датасет
1. Поддерживаются DbNull-значения.
2. Поддерживаются версии строк.
3. Код разбит так чтобы можно было сериализовать отдельные DataTable-ы. Введены функции:
4. Модифицирован тест:
4.1. Тесты переставлены местами и повторяются по 3 раза.
4.2. В DataTable вносятся записи поля в которых периодически содержат DbNull.
4.3. Добавлены записи с разными версиями (удаленные, добавленные, измененные, немодифицированные).
Результат:
1. Время сериализации несколько увеличилось, но не существенно (один фиг быстрее чем у Трентора).
2. Вырос объем данных: По 2 байта на строку плюс если есть другая версия, то ее размер.
Что не поддерживается сериализатором?
1. Индексы и представления (view). Сделать можно, но это тоже время...
2. Вычисляемые поля.
3. Констрэйны.
Возможно я пропустил еще что-то...
Но это все ерунда, так как много времени сериализация остального незаймет, так как остались исключительно декларативные вещи.
Уже в этом виде датасет можно смело использовать в 90% приложений, так как для предачи данных извращения с многотабличностью ненужны. Индексы можно строить и на клиенте (должен же он хоть что-то делать).
using System;
using System.IO;
using System.Data;
using System.Collections;
namespace RSDN
{
class DetaSerializer
{
static readonly DataRowVersion[] _aryVer = new DataRowVersion[2]
{ DataRowVersion.Original, DataRowVersion.Current };
// Массив для перемапливания TypeCode на Type
// TypeCode это перечисление включающее константы для базовых типов.static readonly Type[] _TypeMap;
// Статический конструктор. Нужен для инициализации _TypeMap.static DetaSerializer()
{
// TypeCode.DBNull и TypeCode.Empty пропущены, так как они
// по сути, не являются типами.
_TypeMap = new Type[(int)TypeCode.String + 1];
_TypeMap[(int)TypeCode.Object] = typeof(Object);
_TypeMap[(int)TypeCode.Boolean] = typeof(Boolean);
_TypeMap[(int)TypeCode.Char] = typeof(Char);
_TypeMap[(int)TypeCode.SByte] = typeof(SByte);
_TypeMap[(int)TypeCode.Byte] = typeof(Byte);
_TypeMap[(int)TypeCode.Int16] = typeof(Int16);
_TypeMap[(int)TypeCode.UInt16] = typeof(UInt16);
_TypeMap[(int)TypeCode.Int32] = typeof(Int32);
_TypeMap[(int)TypeCode.UInt32] = typeof(UInt32);
_TypeMap[(int)TypeCode.Int64] = typeof(Int64);
_TypeMap[(int)TypeCode.UInt64] = typeof(UInt64);
_TypeMap[(int)TypeCode.Single] = typeof(Single);
_TypeMap[(int)TypeCode.Double] = typeof(Double);
_TypeMap[(int)TypeCode.Decimal] = typeof(Decimal);
_TypeMap[(int)TypeCode.DateTime] = typeof(DateTime);
_TypeMap[(int)TypeCode.String] = typeof(String);
}
///////////////////////////////////////////////////////////////////////
// Сериализация.public static void SerializeDataSet(Stream stream, DataSet ds)
{
BinaryWriter bw = new BinaryWriter(stream);
DataTableCollection tables = ds.Tables;
bw.Write(ds.DataSetName);
bw.Write(tables.Count);
foreach(DataTable dt in tables)
{ // Вообще-то foreach-и лучше на всякий пожарный избегать.
// Но мне было в лом.
SerializeDataTable(bw, dt);
}
}
public static void SerializeDataTable(BinaryWriter bw, DataTable dt)
{
DataColumnCollection columns = dt.Columns;
int iColCount = columns.Count;
TypeCode[] colTypeCodes = new TypeCode[iColCount];
bool[] aryIsNullabl = new bool[iColCount];
// Имя таблицы
bw.Write(dt.TableName);
bw.Write(iColCount);
// Получаем и записываем описание колонок.for(int i = 0; i < iColCount; i++)
{
DataColumn dc = columns[i];
// Получаем TypeCode для типа обрабатываемой колонки.
TypeCode tc = Type.GetTypeCode(dc.DataType);
// Запоминаем TypeCode колонки в соотвествующем массиве.
colTypeCodes[i] = tc;
bw.Write(dc.ColumnName);
// Записываем TypeCode как Int32. Можно было бы и
// сэкономить 3 байта. :)
bw.Write((Int32)tc);
// Создаем массив информации о поддержке колонками DBNull
aryIsNullabl[i] = dc.AllowDBNull;
}
// Записываем битовое поле описывающее колонки поддерживающие
// DBNull. Если бит поднят, значит, колонка поддерживает DBNull.
BitArray bitsNull = new BitArray(aryIsNullabl);
byte[] byteNull = new byte[(iColCount + 7) / 8];
bitsNull.CopyTo(byteNull, 0);
bw.Write(byteNull);
///////////////////////////////////////////////////////////////
// add data
// count rows
bw.Write(dt.Rows.Count);
// Записываем строкиforeach(DataRow dr in dt.Rows)
{
byte verFlags = 0;
int iVerStart;
int iVerEnd;
// Разбираемся, какие версии нужно писать.
// Всего есть два варианта: Original и Current
DataRowState state = dr.RowState;
switch(state)
{
// Original + Current и они равны!case DataRowState.Unchanged:
iVerStart = 0;
iVerEnd = 0;
verFlags = 0;
break;
case DataRowState.Deleted: // Только Original
iVerStart = 0;
iVerEnd = 0;
verFlags = 1;
break;
case DataRowState.Added: // Только Current
iVerStart = 1;
iVerEnd = 1;
verFlags = 2;
break;
// Original + Current и они НЕ равны!case DataRowState.Modified:
iVerStart = 0;
iVerEnd = 1;
verFlags = 3;
break;
default:
throw new ApplicationException(
"Недопустимое состояние строки: " + state.ToString());
}
// Пишем описание версий. Временно, так как на этом мы
// теряем байт на строку. Куда лучше писать дополнительные два
// бита в битовое поле DbNull (хотя это и не красиво).
bw.Write(verFlags);
// Записываем версии текущей строки. Всего их может быть две.
// в принципе можно было бы для случая DataRowState.Modified
// писать только дельту данных. Но это как-нибудь потом. :)for(int iVetIndex = iVerStart; iVetIndex <= iVerEnd; iVetIndex++)
{
DataRowVersion drv = _aryVer[iVetIndex];
// Создаем и заполняем битовое поле. Если бит поднят,
// значит, соответствующая колонка содержит DBNull.
bitsNull.SetAll(false);
for(int i = 0; i < iColCount; i++)
{
if(dr[i, drv] == DBNull.Value)
bitsNull.Set(i, true);
}
bitsNull.CopyTo(byteNull, 0);
// Записываем битовое поле в стрим.
bw.Write(byteNull);
// Перебираем колонки и пишем данные...for(int i = 0; i < iColCount; i++)
{
// Если колонка содержит DBNull, записывать ее значение
// ненужно.object data = dr[i, drv];
if(data == DBNull.Value) // Учитываем версию!continue;
// Записываем данные ячейки.switch(colTypeCodes[i])
{ // Каждому типу соответствует переопределенная функция...case TypeCode.Boolean: bw.Write((Boolean)data); break;
case TypeCode.Char: bw.Write((Char)data); break;
case TypeCode.SByte: bw.Write((SByte)data); break;
case TypeCode.Byte: bw.Write((Byte)data); break;
case TypeCode.Int16: bw.Write((Int16)data); break;
case TypeCode.UInt16: bw.Write((UInt16)data); break;
case TypeCode.Int32: bw.Write((Int32)data); break;
case TypeCode.UInt32: bw.Write((UInt32)data); break;
case TypeCode.Int64: bw.Write((Int64)data); break;
case TypeCode.UInt64: bw.Write((UInt64)data); break;
case TypeCode.Single: bw.Write((Single)data); break;
case TypeCode.Double: bw.Write((Double)data); break;
case TypeCode.Decimal: bw.Write((Decimal)data); break;
case TypeCode.DateTime:
// Для DateTime приходится выпендриваться особым образом.
bw.Write(((DateTime)(data)).ToFileTime());
break;
case TypeCode.String: bw.Write((String)data); break;
default:
// На всякий случай пробуем записать неопознанный тип
// виде строки.
bw.Write(data.ToString());
break;
}
}
}
}
}
public static void SerializeDataTable(Stream stream, DataTable dt)
{
BinaryWriter bw = new BinaryWriter(stream);
SerializeDataTable(bw, dt);
}
///////////////////////////////////////////////////////////////////////
// Десериализацияpublic static DataTable DeserializeTable(BinaryReader br)
{
DataColumn dc;
DataRow dr;
// Имя DataTable тоже передается в качестве параметра конструктора.
DataTable dt = new DataTable(br.ReadString());
dt.BeginLoadData();
int iColCount = br.ReadInt32();
// В этом массив будут записаны TypeCode-ы для колонок DataTable-а.
TypeCode[] colTypeCodes = new TypeCode[iColCount];
// А в этот массив будут записаны типы (Type) колонок DataTable-а
// соотвествующие TypeCode-ам.for(int c = 0; c < iColCount; c++)
{
string colName = br.ReadString();
// Считываем TypeCode.
TypeCode tc = (TypeCode)br.ReadInt32();
// Помещаем TypeCode в массив для дальнейшего использования.
colTypeCodes[c] = tc;
// Получаем (через мап) тип соответствующий TypeCode-у.
Type type = _TypeMap[(int)tc];
// Создаем колонку с полученным именем и типом.
dc = new DataColumn(colName, type);
dt.Columns.Add(dc);
}
// Считываем список nullabl-колонок.int iBitLenInBytes = (iColCount + 7) / 8;
byte[] byteNull = new byte[iBitLenInBytes];
br.Read(byteNull, 0, iBitLenInBytes);
BitArray bitsNull = new BitArray(byteNull);
bitsNull.Length = iColCount;
bool[] aryIsNullabl = new bool[iColCount];
bitsNull.CopyTo(aryIsNullabl, 0);
object[] ad = new object[iColCount];
int counRows = br.ReadInt32();
DataRowCollection rows = dt.Rows;
for(int r = 0; r < counRows; r++)
{
// Читаем описание версий. Временно, так как на этом мы
// теряем байт на строку.byte verFlags = br.ReadByte();
int iVerStart;
int iVerEnd;
DataRowState drs;
switch(verFlags)
{
// Original + Current и они равны!case 0: // DataRowState.Unchanged
iVerStart = 0;
iVerEnd = 0;
drs = DataRowState.Unchanged;
break;
case 1: // DataRowState.Deleted Только Original
iVerStart = 0;
iVerEnd = 0;
drs = DataRowState.Deleted;
break;
case 2: // DataRowState.Added Только Current
iVerStart = 1;
iVerEnd = 1;
drs = DataRowState.Added;
break;
// Original + Current и они НЕ равны!case 3: // DataRowState.Modified
iVerStart = 0;
iVerEnd = 1;
drs = DataRowState.Modified;
break;
default:
throw new ApplicationException(
"Недопустимое состояние строки. Сбой при загрузке.");
}
// Считываем данные.
dr = dt.NewRow();
rows.Add(dr);
dr.BeginEdit();
// Считываем версии текущей строки.for(int iVetIndex = iVerStart; iVetIndex <= iVerEnd; iVetIndex++)
{
br.Read(byteNull, 0, iBitLenInBytes);
bitsNull = new BitArray(byteNull);
for(int i = 0; i < iColCount; i++)
{
if(bitsNull.Get(i))
{
dr[i] = DBNull.Value;
continue;
}
switch(colTypeCodes[i])
{
case TypeCode.Boolean: dr[i] = br.ReadBoolean(); break;
case TypeCode.Char: dr[i] = br.ReadChar(); break;
case TypeCode.SByte: dr[i] = br.ReadSByte(); break;
case TypeCode.Byte: dr[i] = br.ReadByte(); break;
case TypeCode.Int16: dr[i] = br.ReadInt16(); break;
case TypeCode.UInt16: dr[i] = br.ReadUInt16(); break;
case TypeCode.Int32: dr[i] = br.ReadInt32(); break;
case TypeCode.UInt32: dr[i] = br.ReadUInt32(); break;
case TypeCode.Int64: dr[i] = br.ReadInt64(); break;
case TypeCode.UInt64: dr[i] = br.ReadUInt64(); break;
case TypeCode.Single: dr[i] = br.ReadSingle(); break;
case TypeCode.Double: dr[i] = br.ReadDouble(); break;
case TypeCode.Decimal: dr[i] = br.ReadDecimal(); break;
case TypeCode.DateTime:
dr[i] = DateTime.FromFileTime(br.ReadInt64());
break;
case TypeCode.String: dr[i] = br.ReadString(); break;
default:
dr[i] = Convert.ChangeType(br.ReadString(),
colTypeCodes[i]);
break;
}
}
if(iVetIndex == 0)
{
dr.AcceptChanges();
if(iVerEnd > 0)
dr.BeginEdit();
}
}
if(drs == DataRowState.Deleted)
dr.Delete();
dr.EndEdit();
}
dt.EndLoadData();
return dt;
}
public static DataTable DeserializeTable(Stream stream)
{
BinaryReader br = new BinaryReader(stream);
return DeserializeTable(br);
}
public static DataSet DeserializeDataSet(Stream stream)
{
BinaryReader br = new BinaryReader(stream);
// Считываем имя DataSet и создаем его...
DataSet ds = new DataSet(br.ReadString());
//ds.BeginInit();int counTables = br.ReadInt32();
DataTable dt;
for(int t = 0; t < counTables; t++)
{
dt = DeserializeTable(br);
ds.Tables.Add(dt);
}
//ds.AcceptChanges(); с версиями так нельзя... :)
//ds.EndInit();return ds;
}
}
}
Тест:
using System;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using RSDN;
namespace SerializeTest
{
class Class1
{
static bool IsOriginalVer(DataRow dr)
{
DataRowState state = dr.RowState;
switch(state)
{
// Original + Current и они равны!case DataRowState.Unchanged: return true;
case DataRowState.Deleted: return true;
case DataRowState.Added: return false;
case DataRowState.Modified: return true;
default:
throw new ApplicationException(
"Недопустимое состояние строки: " + state.ToString());
}
}
static bool IsCurrentVer(DataRow dr)
{
DataRowState state = dr.RowState;
switch(state)
{
// Original + Current и они равны!case DataRowState.Unchanged: return true;
case DataRowState.Deleted: return false;
case DataRowState.Added: return true;
case DataRowState.Modified: return true;
default:
throw new ApplicationException(
"Недопустимое состояние строки: " + state.ToString());
}
}
static bool CmpDataSets(DataSet ds1, DataSet ds2)
{
if(!CmpDataTables(ds1.Tables[0], ds2.Tables[0]))
{
Console.WriteLine("DataTable НЕ одинаковые!!!");
return false;
}
return true;
}
// Сравнивает два DataTablestatic bool CmpDataTables(DataTable dt1, DataTable dt2)
{
if(dt1.Rows.Count != dt1.Rows.Count)
return false;
if(dt1.Columns.Count != dt1.Columns.Count)
return false;
int iCols = dt1.Columns.Count;
DataRowCollection rows1 = dt1.Rows;
DataRowCollection rows2 = dt2.Rows;
int iRows = rows1.Count;
for(int r = 0; r < iRows; r++)
{
DataRow dr1 = rows1[r];
DataRow dr2 = rows2[r];
if(IsCurrentVer(dr1))
{
if(!IsCurrentVer(dr2))
return false;
for(int i = 0; i < iCols; i++)
{
if(!dr1[i, DataRowVersion.Current].Equals(
dr2[i, DataRowVersion.Current]))
return false;
}
}
else
if(IsCurrentVer(dr2))
return false;
if(IsOriginalVer(dr1))
{
if(!IsOriginalVer(dr2))
return false;
for(int i = 0; i < iCols; i++)
{
if(!dr1[i, DataRowVersion.Original].Equals(
dr2[i, DataRowVersion.Original]))
return false;
}
}
else
if(IsOriginalVer(dr2))
return false;
}
return true;
}
// Вызывает суровую уборку мусора. :)static void ClearMem()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
[STAThread]
static void Main(string[] args)
{
DataSet ds = new DataSet("myDataSet");
DataTable dt = new DataTable("Table1");
dt.Columns.Add(new DataColumn("col0", typeof(Int32)));
dt.Columns[0].AllowDBNull = false;
dt.Columns.Add(new DataColumn("col1", typeof(string)));
dt.Columns.Add(new DataColumn("col2", typeof(DateTime)));
dt.Columns.Add(new DataColumn("col3", typeof(byte)));
dt.Columns[3].AllowDBNull = false;
DataRow dr;
dt.BeginLoadData();
for(int i = 0; i < 40000; i++)
{
dr = dt.NewRow();
dr.BeginEdit();
dr[0] = i;
// В каждой 100-й строке колонка 1 заполняется DBNull-ом.
dr[1] = i % 100 == 0 ? DBNull.Value : (object)("2test" + i.ToString());
// В каждой 40-й строке колонка 2 заполняется DBNull-ом.
dr[2] = i % 40 == 0 ? DBNull.Value : (object)DateTime.Now;
dr[3] = (byte)i % 255;
dt.Rows.Add(dr);
if(i % 20 == 0)
{
// Каждая 20 строка помечается как отредактированная
dr.AcceptChanges();
dr[0] = i;
}
else if(i % 21 == 0)
{
// Каждая 21 строка помечается как удаленная
dr.AcceptChanges();
dr.Delete();
}
else if(i % 22 != 0)
// Все остальные строки кроме каждой 22 помечаются как
// оригинальные (не модифицированные). Таким обрезом каждая 22
// строка остается помеченной как добавленная.
dr.AcceptChanges();
dr.EndEdit();
}
dt.EndLoadData();
ds.Tables.Add(dt);
//ds.AcceptChanges();
//ds.Tables[0].Rows[0].HasVersion();
// Console.WriteLine(ds.Tables[0].Rows[0].RowState);
// ds.AcceptChanges();
// Console.WriteLine(ds.Tables[0].Rows[0].RowState);
RsdnDetaSerializer(ds);
RsdnDetaSerializer(ds);
RsdnDetaSerializer(ds);
TestBinaryFormatter(ds);
TestBinaryFormatter(ds);
TestBinaryFormatter(ds);
TestXmlSerializer(ds);
TestXmlSerializer(ds);
TestXmlSerializer(ds);
TestSoapFormatter(ds);
TestSoapFormatter(ds);
TestSoapFormatter(ds);
frmDataset frm = new frmDataset();
frm.dataGrid1.DataSource = ds.Tables[0];
frm.ShowDialog();
Console.WriteLine("\nDone!");
Console.ReadLine();
}
static void TestDataSetHandsSerializate(DataSet ds)
{
int start; // Используется для вычисления времени выполнения
ClearMem(); // Вызов GC чтобы небыло налаженки...
// Стрим для ручной сериализации через DetaSetCustomSerializer2.
MemoryStream ms = new MemoryStream(1024);
// Сериализация DataSetHandsSerializate
start = Environment.TickCount;
DataSetHandsSerializate.Serialize(ms, ds);
int timeSerialize = Environment.TickCount - start;
// Загрузка DataSetHandsSerializate
ms.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
DataSet dsLoaded = DataSetHandsSerializate.Deserialize(ms);
Console.WriteLine(
"\n DataSetHandsSerializate\n"
+ "Serialization: {0,10:### ### ###} ms "
+ "Loading: {1,10:### ### ###}\n"
+ "Length is: {2,10:### ### ###}",
timeSerialize, Environment.TickCount - start, ms.Length);
CmpDataSets(dsLoaded, ds);
}
static void RsdnDetaSerializer(DataSet ds)
{
int start; // Используется для вычисления времени выполнения
ClearMem();
// Стрим для ручной сериализации через DataSetHandsSerializate.
MemoryStream ms = new MemoryStream(1024);
// Сериализация DetaSetCustomSerializer2
start = Environment.TickCount;
DetaSerializer.SerializeDataSet(ms, ds);
int timeSerialize = Environment.TickCount - start;
// Загрузка DetaSetCustomSerializer2
ms.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
DataSet dsLoaded = DetaSerializer.DeserializeDataSet(ms);
Console.WriteLine(
"\n RsdnDetaSerializer\n"
+ "Serialization: {0,10:### ### ###} ms "
+ "Loading: {1,10:### ### ###} "
+ "Length: {2,10:### ### ###} bytes",
timeSerialize, Environment.TickCount - start, ms.Length);
// dsLoaded.Tables[0].Rows[2][0] = 123; // проверка CmpDataSets
CmpDataSets(dsLoaded, ds);
// тест.
//frmDataset frm = new frmDataset();
//frm.dataGrid1.DataSource = ds.Tables[0];
//frm.ShowDialog();
}
static void TestBinaryFormatter(DataSet ds)
{
int start; // Используется для вычисления времени выполнения
ClearMem();
// Стрим для сериализации через BinaryFormatter
MemoryStream ms = new MemoryStream(1024);
BinaryFormatter bf = new BinaryFormatter();
// Сериализация BinaryFormatter
start = Environment.TickCount;
bf.Serialize(ms, ds);
int timeSerialize = Environment.TickCount - start;
// Загрузка BinaryFormatter
ms.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
DataSet dsLoaded = (DataSet)bf.Deserialize(ms);
Console.WriteLine(
"\n BinaryFormatter\n"
+ "Serialization: {0,10:### ### ###} ms "
+ "Loading: {1,10:### ### ###} "
+ "Length: {2,10:### ### ###} bytes",
timeSerialize, Environment.TickCount - start, ms.Length);
CmpDataSets(dsLoaded, ds);
}
static void TestXmlSerializer(DataSet ds)
{
int start; // Используется для вычисления времени выполнения
ClearMem();
// Стрим для сериализации через XmlSerializer
MemoryStream ms = new MemoryStream(1024);
// Сериализация XmlSerializer
start = Environment.TickCount;
XmlSerializer serializer = new XmlSerializer(typeof(DataSet));
serializer.Serialize(ms, ds);
int timeSerialize = Environment.TickCount - start;
// Загрузка XmlSerializer
ms.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
DataSet dsLoaded = (DataSet)serializer.Deserialize(ms);
Console.WriteLine(
"\n XmlSerializer\n"
+ "Serialization: {0,10:### ### ###} ms "
+ "Loading: {1,10:### ### ###} "
+ "Length: {2,10:### ### ###} bytes",
timeSerialize, Environment.TickCount - start, ms.Length);
CmpDataSets(dsLoaded, ds);
}
static void TestSoapFormatter(DataSet ds)
{
int start; // Используется для вычисления времени выполнения
ClearMem();
// Стрим для сериализации через SoapFormatter
MemoryStream ms = new MemoryStream(1024);
SoapFormatter sf = new SoapFormatter();
// Сериализация SoapFormatter
start = Environment.TickCount;
sf.Serialize(ms, ds);
int timeSerialize = Environment.TickCount - start;
// Загрузка SoapFormatter
ms.Seek(0, SeekOrigin.Begin);
start = Environment.TickCount;
DataSet dsLoaded = (DataSet)sf.Deserialize(ms);
Console.WriteLine(
"\n SoapFormatter\n"
+ "Serialization: {0,10:### ### ###} ms "
+ "Loading: {1,10:### ### ###} "
+ "Length: {2,10:### ### ###} bytes",
timeSerialize, Environment.TickCount - start, ms.Length);
CmpDataSets(dsLoaded, ds);
}
}
}
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, VladD2, Вы писали:
VD>Всю эту универсальность можно было бы реализовать и без таких страшных провалов производительности. Все что нужно было сделать — это генерировать код сериализации помпилятором,
Это возможно если заранее известно какие конкретно объекты будут сериализоваться. А это приведет к XmlSerializer, для которого сериализуемые данные нужно заранее размечать.
Здравствуйте, VladD2, Вы писали:
VD>Блин, твой необоснованный оптимизм просто поражает. Посмотри на результат Трентора. Он между прочем просто текст писал. Если в его код вставить теги и именами олей, то будет тот же эффект, что и с XMLWriter. С загрузкой то же фигня.
Здравствуйте, AndrewVK, Вы писали:
AVK>Это возможно если заранее известно какие конкретно объекты будут сериализоваться. А это приведет к XmlSerializer, для которого сериализуемые данные нужно заранее размечать.
Вовсе нет. Просто код должен будет генерироваться для каждого типа плюс для массива содержащего этот тип. Если будет какой-нить object, нужно будет всего-лишь прочитать его тип и найти соотвествующий сериализатор. В общем хеш-таблицы нам помогут.
Интересно насколько тормозит сериализация в Яве?
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, VladD2, Вы писали:
VD>Вовсе нет. Просто код должен будет генерироваться для каждого типа плюс для массива содержащего этот тип. Если будет какой-нить object, нужно будет всего-лишь прочитать его тип и найти соотвествующий сериализатор. В общем хеш-таблицы нам помогут.
То есть ты предлагаешь генерить сериализатор при первом обращении к конкретному классу?
VD>Интересно насколько тормозит сериализация в Яве?
VD>>Всю эту универсальность можно было бы реализовать и без таких страшных провалов производительности. Все что нужно было сделать — это генерировать код сериализации помпилятором,
AVK>Это возможно если заранее известно какие конкретно объекты будут сериализоваться. А это приведет к XmlSerializer, для которого сериализуемые данные нужно заранее размечать.
Вообще-то, можно было реализовывать ISerializable. Прямо там, где генерируется код для typed dataset, в Visual Studio. Можно было, но они на этом решили сэкономить. Ну и хрен с ним.
... << RSDN@Home 1.0 beta 6a >>
Re[12]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, AndrewVK, Вы писали:
AVK>То есть ты предлагаешь генерить сериализатор при первом обращении к конкретному классу?
Оптимально было бы это делать еже при компиляции типа. Встретили атрибут Serialazable... и сгенерили код сериализации. Оптимальный и шустрый. При этом ожно было бы создавать два варианта сериализации толернтный к версии и скоростной. Первый использовать при сериализации в файл, а второй в ремоутинге и других местах где скорость самый важный показатель.
VD>>Интересно насколько тормозит сериализация в Яве?
AVK>Вот как то не интересовался.
А было бы интересно сравнить. За одно сравнить с реализацией на плюсах. В дотнете даже BinaryReaded/BinaryWriter написаны далеко не оптимально (вместо адресной арифметики используются операторы сдвига).
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: Сериализация в дотнете 2 - самопальный датасет
Здравствуйте, mihailik, Вы писали:
VD>> В дотнете даже BinaryReaded/BinaryWriter написаны далеко не оптимально (вместо адресной арифметики используются операторы сдвига).
M>Ух ты, интерестно! А как это?
У тебя что Анакрины нет? Или исходников Ротора?
Вот так:
public virtual void Write(int value)
{
this._buffer[0] = (byte) value;
this._buffer[1] = (byte) value >> 8;
this._buffer[2] = (byte) value >> 16;
this._buffer[3] = (byte) value >> 24;
this.OutStream.Write(this._buffer, 0, 4);
}
Вместо банального С++-ного:
public virtual void Write(int value)
{
memcpy(_buffer, &value, sizeof(value));
}
... << RSDN@Home 1.0 beta 6a >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.