I have a small morale from today. I was writing some code that was handling searching for items base also on CultureInfo. Because it’s a pretty straightforward object, in core of .NET Framework (it’s in mscorlib) I was expecting to handle equality using == based on culture itself not the object. And of course, I was wrong.
The code below should explain it clearly (CurrentUICulture might be different based on your system).
// false
System.Threading.Thread.CurrentThread.CurrentUICulture == System.Globalization.CultureInfo.GetCultureInfo("en-US");
// true
System.Threading.Thread.CurrentThread.CurrentUICulture.Equals(System.Globalization.CultureInfo.GetCultureInfo("en-US"));
Yep. Learning something every day.
Often, when you discover the beauty of multithreading and parallelism, you find a need to run some operations in parallel and wait for completion. Fairly common scenario. Although now, with .NET Framework 4, you can write it using Task Parallel Library‘s Parallel.Invoke, there are scenarios when you need to plug it in into some other methods/parameters, so you’ll do it yourself explicitly with threads or better to say ThreadPool.
The method I see from time to time looks basically like this:
void DoSomethingExample()
{
int numberOfActions = 10;
ManualResetEvent[] mres = new ManualResetEvent[numberOfActions];
for (int i = 0; i < numberOfActions; i++)
{
mres[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem((o) =>
{
Thread.SpinWait(20000000);
(o as ManualResetEvent).Set();
},
mres[i]);
}
ManualResetEvent.WaitAll(mres);
}
Though it’s not wrong, except the ManualResetEvents are not Disposed, it’s suboptimal. You’re wasting resources creating array of these objects.
But if you think about it, you can write it better. Better in a way for scaling, performance and memory consumption.
void DoSomethingBetter()
{
int numberOfActions = 10;
using (ManualResetEvent mre = new ManualResetEvent(false))
{
for (int i = 0; i < numberOfActions; i++)
{
ThreadPool.QueueUserWorkItem((o) =>
{
Thread.SpinWait(20000000);
if (Interlocked.Decrement(ref numberOfActions) == 0)
mre.Set();
},
null);
}
mre.WaitOne();
}
}
I’m simply using one synchronization object (and using using statement
), because I’m really interested in only when all tasks are done (one stuff), and decrementing the total number of tasks every time one finishes. Using Interlocked class I’m sure no race condition will occur and I’ll get the right results. After it reaches zero I’m signaling I’m done and the method can continue.
Fewer resources, atomic operations usage … better/faster results.
Dneska jsem se dostal opět k velmi vtipnému řešení problému v relační databázi (to jsem to hezky napsal, ale ve skutečnosti jde o prasácky vyrobenou tabulku(y) vyústivší v prasácké selecty).
No schválně. Jak budete řešit přiřazení položky do kategorií? Ano, například jednoduchá tabulka (id_item, id_kategorie). Ale to je řešení běžné… Vskutku vtipné řešení, je přidat k položce sloupec, který obsahuje znakem, např. ‘|’, oddělené hodnoty. Pak máte velmi výkonný select ‘SELECT * FROM tabulka WHERE (kategorie LIKE ‘%|12345|%’) ORDER BY id’ (nad “select *” se již nepozastavuji).
No to si pak užijeme legrace s sql serverem, že?
Dnešním příspěvkem bych chtěl ukázt, proč nemám MySQL resp. uživatele MySQL rád. Není to špatná DB, ale špatné jméno jí dělají uživatelé, kteří často postrádají základní znalosti a bohužel je jich obrovská masa, takže “je to vidět”.
Dnes kolega řešil zhoršený výkon jednoho z sql serverů, kde beží výhradně MySQL. Po chvilce pátrání se ukázalo, že prezentace běžící na webovém serveru, potřebuje vypisovat počet inzerátů k zobrazení. “Programátor” tvořící aplikaci to vyřešil vskutku kulišácky. Příkazem SELECT * FROM inzeraty WHERE zobrazovat='1' vydloubal z DB všechny záznamy, přenesl je z sql serveru na webový a prostě ve smyčce spočítal inkrementací proměnné. Velmi elegantní.
Kolik chyb je v uvedeném postupu můžete spočítat za domácí úkol. No doufám, že další takovéto případy nebudu muset prezentovat často.