PDA

View Full Version : افزایش سرعت پردازش برنامه در C#



md3848
دوشنبه 25 آذر 1398, 21:15 عصر
سلام - من یه برنامه نوشتم که عدد 0بیت تا 64 بیت، رو میاد دونه دونه محاسبات انجام میده و در DataGridView اضافش میکنه البته از DataTable استفاده میکنم تا اطلاعات داخل DataTable ذخیره بشه، آخرسر که محاسبات تموم شد، میام DataTable فوق رو به DataGridView میدم ( فعلا با قسمت مانیتورینگ داده کاری ندارم / کد این قسمت رو هم حذف کردم، بازم سرعت محاسبات خیلی کم بود ) - مشکل اینجاس که سرعت کار خیلی کمه؛ خواستم ببینم چیکار باید کنم؟ با بحث Treath میشه حلش کرد؟ یا این که روش دیگه رو باید برم؟

the king
دوشنبه 25 آذر 1398, 22:08 عصر
سلام - من یه برنامه نوشتم که عدد 0بیت تا 64 بیت، رو میاد دونه دونه محاسبات انجام میده و در DataGridView اضافش میکنه البته از DataTable استفاده میکنم تا اطلاعات داخل DataTable ذخیره بشه، آخرسر که محاسبات تموم شد، میام DataTable فوق رو به DataGridView میدم ( فعلا با قسمت مانیتورینگ داده کاری ندارم / کد این قسمت رو هم حذف کردم، بازم سرعت محاسبات خیلی کم بود ) - مشکل اینجاس که سرعت کار خیلی کمه؛ خواستم ببینم چیکار باید کنم؟ با بحث Treath میشه حلش کرد؟ یا این که روش دیگه رو باید برم؟

کندی مربوط به کدوم قسمت کار شما است؟ اگه مربوط به محاسبه کردن اون 64 بیتی ها باشه، احتمال داره با Thread و Parallel بتوانید در چند نخ اجراشون کنید و سرعت تولید داده رو بالا ببرید.
میگم احتمال داره چون الگوریتم محاسباتی شما رو نمیدونم و همه الگوریتم ها رو نمیشه بصورت اجرای موازی در چند نخ تفسیم کرد.
اما اگر کندی مربوط به درج در DataTable یا DataGridView باشه، نه. چون فقط یک DataTable و DataGridView باید پر بشه، چند تا نخ برای پر کردنش کمکی نمی کنه.

اما DataGridView قابلیت VirtualMode داره. این قابلیت بهش این امکان رو میده که بتونه داده هایی رو نمایش بده که از اول بصورت کامل بهش تحویل داده نشدن یا بصورت حتی کامل تولید نشدن.
وقتی VirtualMode اش فعال شد، دیگه فقط براش مهمه که شما چند تا سطر و ستون داده دارید، داده ها رو نمیخواد. بجاش یک رخدادی به نام CellValueNeeded داره که میگه من الان در این لحظه داده فلان خانه رو میخوام تا نمایش بدم.
پشما می توانید اون داده رو همون لحظه براش بسازید و داخل متد رخداد تحویل بدید، لازم نیست داده رو از قبل محاسبه کنید.
اصولا هر کنترلی که داده رو بصورت Virtual دریافت می کنه در هر لحظه از شما صرفا داده ای رو میخواد که داره نمایش میده، ممکنه تعداد سطر هاش میلیونی باشه، ولی هر لحظه فقط 40 تا سطر رو نشون بده و از شما هم فقط داده اون 40 سطر رو میخواد.
شما در برخی موارد می توانید به همین طریق از DataGridView استفاده کنید، داده هاتون رو همون موقع محاسبه کنید که DataGridView میخواد نمایش شون بده، نه همه شون رو. فقط همونی که در کادر نمایش داده میشه.

md3848
دوشنبه 25 آذر 1398, 22:16 عصر
نه کد ساده ای هستش، از مقدار 0bit تا 64bit ( که مقدار حداکثرش هستش ) میاید مقدار CRC داده رو حساب میکنه / حالا فعلا قسمت سرعت محاسبات رو حل کنم، نمایشش بمونه برای بعد / الان بین این روشایی که گفتید کدومش مناسبتره بنظرتون؟
البته من نیازم بیشتر از 64 بیت ( 8 بایت! ) هستش ولی خب فعلا به همین مقدار اکتفا کردم تا پروژه ساده تر بشه! ( نیاز من 200 بایت هستش ولی دوست دارم محدودیتی نداشته باشم در این قسمت! )


// Calulate CRC
for (UInt64 Data_Dec = 0; Data_Dec < maxDataValue; Data_DeC++‎‎‎‎‎‎‎‎‎‎‎‎)
{
Data_Hex = Data_Dec.ToString("X");
if (Data_Hex.Length % 2 == 1) Data_Hex = "0" + Data_Hex;
Data_Byte = StringToByteArray(Data_Hex.Replace("0x", ""));






if (rb_CRC8bit.Checked)
{
CRC8 = Compute_CRC8(Data_Byte);
CRC_Hex = CRC8.ToString("X");
if (CRC_Hex.Length % 2 == 1) CRC_Hex = "0" + CRC_Hex;
while (CRC_Hex.Length < 2) CRC_Hex = "0" + CRC_Hex;
//---
dataTable.Rows.Add(Data_Dec, CRC_Hex);
}
else if (rb_CRC16bit.Checked)
{
CRC16 = Compute_CRC16(Data_Byte);
CRC_Hex = CRC16.ToString("X");
if (CRC_Hex.Length % 2 == 1) CRC_Hex = "0" + CRC_Hex;
while (CRC_Hex.Length < 4) CRC_Hex = "0" + CRC_Hex;
//---
dataTable.Rows.Add(Data_Dec, CRC_Hex);
}
else if (rb_CRC32bit.Checked)
{
CRC32 = Compute_CRC32(Data_Byte);
CRC_Hex = CRC32.ToString("X");
if (CRC_Hex.Length % 2 == 1) CRC_Hex = "0" + CRC_Hex;
while (CRC_Hex.Length < 8) CRC_Hex = "0" + CRC_Hex;
//---
dataTable.Rows.Add(Data_Dec, CRC_Hex);
}






progressBar1.Value = (int)((1000 * Data_Dec) / maxDataValue);
}

the king
سه شنبه 26 آذر 1398, 13:35 عصر
نه کد ساده ای هستش، از مقدار 0bit تا 64bit ( که مقدار حداکثرش هستش ) میاید مقدار CRC داده رو حساب میکنه / حالا فعلا قسمت سرعت محاسبات رو حل کنم، نمایشش بمونه برای بعد / الان بین این روشایی که گفتید کدومش مناسبتره بنظرتون؟
البته من نیازم بیشتر از 64 بیت ( 8 بایت! ) هستش ولی خب فعلا به همین مقدار اکتفا کردم تا پروژه ساده تر بشه! ( نیاز من 200 بایت هستش ولی دوست دارم محدودیتی نداشته باشم در این قسمت! )


// Calulate CRC
for (UInt64 Data_Dec = 0; Data_Dec < maxDataValue; Data_DeC++‎‎‎‎‎‎‎‎‎‎‎‎‎ ‎)
{
Data_Hex = Data_Dec.ToString("X");
if (Data_Hex.Length % 2 == 1) Data_Hex = "0" + Data_Hex;
Data_Byte = StringToByteArray(Data_Hex.Replace("0x", ""));






if (rb_CRC8bit.Checked)
{
CRC8 = Compute_CRC8(Data_Byte);
CRC_Hex = CRC8.ToString("X");
if (CRC_Hex.Length % 2 == 1) CRC_Hex = "0" + CRC_Hex;
while (CRC_Hex.Length < 2) CRC_Hex = "0" + CRC_Hex;
//---
dataTable.Rows.Add(Data_Dec, CRC_Hex);
}
else if (rb_CRC16bit.Checked)
{
CRC16 = Compute_CRC16(Data_Byte);
CRC_Hex = CRC16.ToString("X");
if (CRC_Hex.Length % 2 == 1) CRC_Hex = "0" + CRC_Hex;
while (CRC_Hex.Length < 4) CRC_Hex = "0" + CRC_Hex;
//---
dataTable.Rows.Add(Data_Dec, CRC_Hex);
}
else if (rb_CRC32bit.Checked)
{
CRC32 = Compute_CRC32(Data_Byte);
CRC_Hex = CRC32.ToString("X");
if (CRC_Hex.Length % 2 == 1) CRC_Hex = "0" + CRC_Hex;
while (CRC_Hex.Length < 8) CRC_Hex = "0" + CRC_Hex;
//---
dataTable.Rows.Add(Data_Dec, CRC_Hex);
}






progressBar1.Value = (int)((1000 * Data_Dec) / maxDataValue);
}

مثال پیوستی رو ببینید :
151140
در ظاهر DataGridView مون به تعداد ناچیز 9223372036854775807 سطر داره، یعنی ulong.MaxValue، اما در حقیقت تعداد سطر های DataGridView همونقدر ئه که در صفحه نمایش می بینید. برای همین هم سرعت اجراش فوق العاده بالا است.
اما چون ScrollBar های عادی نمی توانند محدوده بزرگتر از int رو پوشش بدن، نمی توانستیم روی ScrollBar خود DataGridView حسابی باز کنیم. بجایش از یک کلاس ScrollBar خاص استفاده کردم که بازه decimal قبول می کنه که از ulong هم بزرگتره.
کد منبع پایه ScrollBar ئه اینجا (https://www.codeproject.com/Articles/624997/Enhanced-Scrollbar) است و من هم یک دستی به سر و روش کشیدم و بخش های اضافیش رو هم حذف کردم.

151139

در نظر بگیرید که CRC محاسباتش یک مقدار اولیه داره و یک مقدار polynomial و یک مقداری که ممکنه در انتها باهاش xor بشه و در ضمن ممکنه ترتیب بیت ها برعکس باشه (LSB و MSB).
اینکه این سه پارامتر چی باشه و LSB باشه یا MSB، روی نتیجه محاسبه اش خیلی تاثیر داره.
متاسفانه مقدار این سه پارامتر هم همه جا یکسان نیست، برای همین CRC گونه های مختلفی داره، فرضا چند جور CRC16 شناخته شده داریم با پارامتر های متفاوت.
151140

md3848
سه شنبه 26 آذر 1398, 14:41 عصر
خیلی ممنون از لطف شما - من تا 6 دیشب بیدار بودم آخرش هم ...
برنامه تون رو تست کردم، سرعتش یکم غیر طبیعی هستش :لبخند: ( زیادی زیاده! )

==================================================

یه موردی - مثلا داده مون 200 بایت هستش؛ مثلا از CRC8 استفاده میکینم، خب اینطوری از یه جایی به بعد، CRC هامون تکراری میشه که - یعنی برا داده 200 بایتی x و y ممکنه crc یکسانی داشته باشیم
و این وسط اگه داده x بفرستیم مثلا، ولی از اثر نویز داده y بگیریم ( حال با توجه به این که crc های این دو یکسان هستش )، نمیشه که متوجه رخ دادن خطا شد
برا حل این مشکل چیکار میشه کرد؟
حالا شاید یکی بگه از CRC16 که 2 بایتی هستش استفاده کن؛ خب داده 2 بایتی بین 0 تا 65535 هستش، خب داده ما 200 بایت هستش، 200 بایت بین 0 تا aaaaaaaaaaa ( یه عدد خیلی بزرگتر از 65535 ) هستش و طبیعتا بازم این crc16 از یه جایی به بعد تکرار میشه و باز داستان قبلی.

==================================================

the king
سه شنبه 26 آذر 1398, 19:43 عصر
خیلی ممنون از لطف شما - من تا 6 دیشب بیدار بودم آخرش هم ...
برنامه تون رو تست کردم، سرعتش یکم غیر طبیعی هستش :لبخند: ( زیادی زیاده! )

==================================================

یه موردی - مثلا داده مون 200 بایت هستش؛ مثلا از CRC8 استفاده میکینم، خب اینطوری از یه جایی به بعد، CRC هامون تکراری میشه که - یعنی برا داده 200 بایتی x و y ممکنه crc یکسانی داشته باشیم
و این وسط اگه داده x بفرستیم مثلا، ولی از اثر نویز داده y بگیریم ( حال با توجه به این که crc های این دو یکسان هستش )، نمیشه که متوجه رخ دادن خطا شد
برا حل این مشکل چیکار میشه کرد؟
حالا شاید یکی بگه از CRC16 که 2 بایتی هستش استفاده کن؛ خب داده 2 بایتی بین 0 تا 65535 هستش، خب داده ما 200 بایت هستش، 200 بایت بین 0 تا aaaaaaaaaaa ( یه عدد خیلی بزرگتر از 65535 ) هستش و طبیعتا بازم این crc16 از یه جایی به بعد تکرار میشه و باز داستان قبلی.

==================================================
احتمالش البته خیلی کمه که CRC بخاطر یکی دو بایت اختلاف یکسان باشه، اون ورودی هایی که CRC یکسان دارند یا عمدا CRC خاصی در ابتدا یا انتها داده دارن که دقیقا همون CRC تولید بشه یا داده ها تفاوت خیلی زیادی دارن که در حد نویز نیست.
اما بله. میتونه یکسان باشه. شما هر الگوریتم Hash ساده و پیچیده ای رو انتخاب کنید به هر حال n بیت نمیتونه برای n ^ m نمونه رابطه یک به یک باشه و اشتراک پیش میاد. شما نمی توانید با هیچ Hash ای از اینکار جلوگیری کنید.
اما هر چقدر Hash بزرگتر باشه طبعا برخورد به داده تکراری احتمالش کمتر میشه اما به هر حال هر نمونه Hash با بینهایت نمونه داده ورودی مطابقت داره، چه 8 بیتی باشه و چه 8000 بیتی.