воскресенье, 24 октября 2010 г.

Perfomance Counter. Счетчик производительности

Когда мы хотим измерить производительность кода, нас интересует время, потраченое на его выполнение. Для этого можно "запомнить" время ДО, и время ПОСЛЕ, вычислить разницу и анализировать результат. В этом случае считается, что процессор все время будет выполнять только этот код. Но на практике может получится так, что во время выполения поток дойдет до середины, процессор переключится на другие потоки, обойдет их, и через некоторое время вернется к нашему. Естественно измерения в этом случае некорректны.

С учетом вышеизложенного, для точных расчетов я использую следующий класс (сперто где-то с просторов интернета):

  class PerfCounter
  {
    private static TimeSpan spStartKernelTime;
    private static TimeSpan spStartUserTime;
    private static ProcessThread procThread;
    private static Int32 idCurrentThread;

    [DllImport("kernel32.Dll", SetLastError = true)]
    public static extern UInt32 GetCurrentThreadId();
    public static bool StartCountOnThread()
    {
      idCurrentThread = (Int32)GetCurrentThreadId();
      try
      {
        foreach (ProcessThread prThread in Process.GetCurrentProcess().Threads)
        {
          if (prThread.Id == idCurrentThread)
          {
            procThread = prThread;
            spStartKernelTime = prThread.TotalProcessorTime;
            spStartUserTime = prThread.UserProcessorTime;
            return true;
          }
        }
      }
      catch (System.Exception e)
      {
        System.Console.WriteLine(e.Message);
        //System.Windows.Forms.MessageBox.Show(e.Message);
        return false;
      }
      return false;
    }

    public static TimeSpan FinishCountOnThread()
    {
      try
      {
        foreach (ProcessThread prThread in Process.GetCurrentProcess().Threads)
        {
          if (prThread.Id == idCurrentThread)
          {
            return prThread.TotalProcessorTime +
             prThread.UserProcessorTime -
             spStartKernelTime - spStartUserTime;
          }
        }
      }
      catch (System.Exception e)
      {
        //System.Windows.Forms.MessageBox.Show(e.Message);
        System.Console.WriteLine(e.Message);
        return TimeSpan.Zero;
      }
      return TimeSpan.Zero; ;

    }
  }


* This source code was highlighted with Source Code Highlighter.

воскресенье, 17 октября 2010 г.

Ранкинг (Ranking). SQL запросы с рангом (Rank).

Ранкинг (Ranking) - это предоставление информации о соответствии найденной записи определенному запросу. Это соответствие в простейшем случае можно отобразить в процентном соостветсвии. Т.е. записи удовлетворяющие всем критериям имеют 100%-ный ранкинг.

Реализация ранкинга может показаться достаточно сложной задачей. Но это только так кажется. SQL может взять эту задачу на себя! Для примера я использовал MySQL, реально использовал MSSQL.

Итак, таблица:
CREATE TABLE `test_db`.`person` (
`id` INT NOT NULL,
`name` VARCHAR (100),
`age` int ,
PRIMARY KEY (`id`)
)

Наполним данными:
INSERT INTO test_db.person VALUES (1,'Ralf', 20),(2,'Peter', 30),(3,'Patrick', 40);

Найдем записи, которые соответсвуют одному из трех критериев:
- все старше 25;
- все младше 35;
- имена начинаются на "P";

Запрос может выглядеть так:
SELECT p.id, p.name, p.age FROM test_db.person p
WHERE age > 25 OR age < 35 OR name Like 'P%'


А результат запроса, так:
id, name, age
------------
1,'Ralf', 20
2,'Peter', 30
3,'Patrick',40

Добавим ранкинг (ranking). Объяснять не буду, все очень просто:
SELECT p.id, p.name, p.age, (100/3)*under1.hit + (100/3)*under2.hit + (100/3)*under3.hit AS rank FROM test_db.person p
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age > 25) AS under1 On under1.id = p.id
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age < 35) AS under2 On under2.id = p.id LEFT JOIN (Select id, 1 As hit from test_db.person WHERE name like 'p%') AS under3 On under3.id = p.id WHERE age > 25 OR age < 35 OR name like 'p%'


Результат:
id, name, age, rank
------------
1,'Ralf', 20, null
2,'Peter', 30, null
3,'Patrick', 40, null

Почти то, что нужно, но есть проблема с приведением арфиметического результа к null:
Для этого в MySql можно использовать функцию IFNULL (в MSSQL это функция ISNULL):
SELECT p.id, p.name, p.age, (100/3)*IFNULL(under1.hit, 0) + (100/3)*IFNULL(under2.hit,0) + (100/3)*IFNULL(under3.hit,0) AS rank FROM test_db.person p
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age > 25) AS under1 On under1.id = p.id
LEFT JOIN (Select id, 1 As hit from test_db.person WHERE age < 35) AS under2 On under2.id = p.id LEFT JOIN (Select id, 1 As hit from test_db.person WHERE name like 'p%') AS under3 On under3.id = p.id WHERE age > 25 OR age < 35 OR name like 'p%'


Результат:
id, name, age, rank
------------
1,'Ralf', 20, 33.333
2,'Peter', 30, 100.000
3,'Patrick', 40, 66.666

суббота, 16 октября 2010 г.

Запуск дополнительного X-Server.

Обычно Linux десктоп дистрибутив запускает одну инстанцию X-Server, которая работает в "7"-ом терминале (Alt+Ctrl+F7). Эта инстанция работает с первым X-дисплеем (X-Display). Чтобы запустить программу в другой инстанции нужно:
  • выбрать нужный терминал (Alt+Ctrl+Fx)
  • войти в терминал под своим именем паролем
  • $ xinit _prg_ -- :1 (здесь :1 - номер следующего свободного X-дисплея, нумерация с нуля)

Примеры:
$ xinit gedit -- :1
$ xinit nexuiz -- :1

Замечания:
  • Так можно запускать игры или "проблемные" программки, которые приводят с сбою графического сервера;
  • Окна программ не имеют атрибутов вашего рабочего окружения (GNOME, KDE);
  • Закрытие зависших программ - Ctrl+C
  • Информация должна быть действительна во многих Linux-дистрибутивах, проверено на Ubuntu 10.10 (64bit)

среда, 6 октября 2010 г.

XDocument. Работа с элементами без явного указания пространства имен по умолчанию (Default Namespace)

Если вы используете XDocument, Xml которого содержит явное пространство имен по умолчанию, то во время разбора элементов придется его явно указывать. Для ясности кусочки кода:
<Data xmlns="http://selo-blog.blogspot.com/">
 <Name>Иван</Name>
 <Gender>мужской</Gender>
</Data>

Чтобы получить значение тега "Name", придется выполнить следующий код:
XDocument xDoc = XDocument.Parse(inputString);
XNamespace xSpace = "http://selo-blog.blogspot.com/";
String name = xDoc.Root.Element(xSpace + "Name").Value;

Немного раздражительно, не правда ли?

Для облегчения страданий я создал следующие методы-расширения
public static class Extensions {
  public static XElement xElement(this XElement xParent, String name) {
    return xParent.Element(xParent.Name.Namespace + name);
  }

  public static IEnumerable<XElement> xElements(this XElement xParent, String name) {
    return xParent.Elements(xParent.Name.Namespace + name);
  }
}

Теперь работа с документом происходит обычным способом:
String name = xDoc.Root.xElement("Name").Value;

* This source code was highlighted with Source Code Highlighter.

понедельник, 20 сентября 2010 г.

WinForms. Простой доступ к контексту приложения.

Что бы обеспечить простой досуп к контексту приложения (ApplicationContext) я использовал слудующий подход:

public class AppContext : ApplicationContext
{
  public static AppContext Current { get; private set; }

  public AppContext() {
    if (Current == null)
      Current = this;

    this.init();
  }

  public AppContext(Form mainForm) : this() {
    this.MainForm = mainForm;
  }

  private void init() {
    // ...
  }

  int i = 0;
  public int I { get { return i++; } }
}


* This source code was highlighted with Source Code Highlighter.

Ну и теперь, собственно, в любом месте приложения:
MessageBox.Show(AppContext.Current.I + "");

понедельник, 5 июля 2010 г.

MS SQL. Замена NULL на другие значения

Встретился с небольшой проблемкой, когда в математическом выражении один из операндов является NULL, то результат выражения становится нуль. Вот нашел на просторах интернета по этому поводу следующую информацию. А мне нужно было интерпретировать NULL в 0. Для этого, к счастью, есть в MS SQL функция:
ISNULL ( check_expression , replacement_value )

Например:
SELECT Description, DiscountPct, MinQty, ISNULL(MaxQty, 0.00) AS 'Max Quantity'
FROM Sales.SpecialOffer;

среда, 19 мая 2010 г.

Стандартные операторы запросов LINQ. Справочник

Эту информацию я скомуниздил здесь.

Агрегатные функции

Aggregate
Применяет к последовательности пользовательский метод.

Average
Вычисляет среднее для числовой последовательности.

Count
Возвращает количество элементов в последовательности (целочисленное значение).

LongCount
Возвращает количество элементов в последовательности (значение в диапазоне LongInt).

Min
Возвращает наименьшее значение для числовой последовательности.

Max
Возвращает наибольшее значение для числовой последовательности.

Sum
Складывает члены числовой последовательности.

Конкатенация

Concat
Соединяет две последовательности в одну.

Преобразование

Cast
Преобразует элементы последовательности в элемены указанного типа.

OfType
Выбирает из элементов последовательности элемены указанного типа.

ToArray
Возвращает массив из элементов последовательности.

ToDictionary
Возвращает словарь из элементов последовательности.

ToList
Возвращает список из элементов последовательности.

ToLookup
Возвращает результаты поиска по последовательности.

ToSequence
Возвращает последовательность IEnumerable.

Элемент

DefaultIfEmpty
Создает стандартный элемент для пустой последовательности.

ElementAt
Возвращает элемент последовательности по указанному индексу.

ElementAtOrDefault
Возвращает элемент по указанному индексу или стандартный элемент (если индекс вышел за пределы диапазона).

First
Возвращает первый элемент последовательности.

FirstOrDefault
Возвращает первый элемент последовательности или стандартный элемент (если нужный элемент не найден).

Last
Возвращает последний элемент последовательности.

LastOrDefault
Возвращает последний элемент последовательности или стандартный элемент (если нужный элемент не найден).

Single
Возвращает единственный элемент последовательности.

SingleOrDefault
Возвращает единственный элемент последовательности или стандартный элемент (если нужный элемент не найден).

Равенство

SequenceEqual
Проверяет эквивалентность двух последовательностей.

Создание

Empty
Создает пустую последовательность.

Range
Создает последовательность в соответствии с заданным диапазоном.

Repeat
Создает последовательность, повторяя значение заданное количество раз.

Группировка

GroupBy
Группирует элементы последовательности указанным образом.

Присоединение

GroupJoin
Выполняет группированное соединение двух последовательностей.

Join
Выполняет внутреннее соединение двух последовательностей.

Упорядочение

OrderBy
Упорядочивает элементы последовательности по заданным значениям в порядке возрастания.

OrderByDescending
Упорядочивает элементы последовательности по заданным значениям в порядке убывания.

ThenBy
Упорядочивает элементы уже упорядоченной последовательности в порядке возрастания.

ThenByDescending
Упорядочивает элементы уже упорядоченной последовательности в порядке убывания.

Reverse
Зеркально отображает порядок расположения элементов в последовательности.

Разделение на части

Skip
Возвращает последовательность, в которой указанное число элементов пропущено.

SkipWhile
Возвращает последовательность, в которой пропущены элементы, не соответствующие указанному условию.

Take
Возвращает последовательность, в которую включается указанное число элементов.

TakeWhile
Возвращает последовательность, в которую включаются элементы, соответствующие указанному условию.

Проекция

Select
Создает проекцию части последовательности.

SelectMany
Создает проекцию части последовательности по принципу «один ко многим».

Кванторы

All
Определяет соответствие всех элементов последовательности указанным условиям.

Any
Определяет, есть ли в последовательность элементы, удовлетворяющие указанным условиям.

Contains
Определяет, есть ли в последовательности указанный элемент.

Ограничение

Where
Сортирует члены последовательности.

Настройка

Distinct
Возвращает последовательность без повторяющихся элементов.

Except
Возвращает последовательность, представляющую собой разность двух других последовательностей.

Intersect
Возвращает последовательность, представляющую собой пересечение двух других последовательностей.

Union
Возвращает последовательность, представляющую собой объединение двух других последовательностей.