210 / 134 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
1

Использовать один блок try{} вместо двух, сохраняя производительность

26.09.2012, 11:38. Показов 1061. Ответов 9
Метки нет (Все метки)

LeniumSoft, а как бы вы переработали вот этот метод? Как видите, тут я кучу блоков try{} тоже наставил... Сделал я это по той причине, чтобы при каждом сохранении скрина не проверять существование папки (лишние операции с файловой системой ведь очень дорогостоящие по ресурсам). А если папка не существует, то возникнет исключение, и только уже после этого мы проверим, существует ли папка. И если нет, тогда создаем ее и пробуем вторую попытку создания скрина.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
        private void SaveScreen(Bitmap bitmap, string fileName, string datePath, EncoderParameters encParams)
        {
            while (true) //При нормальной работе без исключений этот цикл проходит только один раз
            {
                try
                {
                    bitmap.Save(fileName, jgpEncoder, encParams);
                    break; //Сохранение скрина прошло успешно. Выходим из цикла
                }
                catch (Exception ex)
                {
                    if (!Directory.Exists(datePath))//если исключение возникло по той причине, что не существовало папки для скринов
                    {
                        try
                        {
                            //тогда пробуем ее создать
                            Directory.CreateDirectory(datePath);
                        }
                        catch (Exception exep)
                        {
                            //не получилось создать папку, потому записываем в лог сообщение об ошибке и выходим из цикла так и не сохранив скрин...
                            Debugging.LogError(exep, "Folder for screens can't created: " + datePath);
                            break;
                        }
                    }
                    else
                    {
                        //произошла неизвестная ошибка сохранения скрина, потому записываем в лог сообщение об ошибке и выходим из цикла так и не сохранив скрин...
                        Debugging.LogError(ex, "Error saving screen in file " + fileName);
                        break;
                    }
                }
            }
            // метод SaveScreen() не вызывается, когда bitmap == null, потому в данном месте я проверку на null во второй раз опустил
            //еще.. Я не вызывал Dispose() в блоке finally выше по той причине, так как цикл while выполнится по второму кругу, если не существовало папки для кринов, чтобы сохранить скрин в только что созданную папку
            bitmap.Dispose();
        }
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.09.2012, 11:38
Ответы с готовыми решениями:

Jugged (ступенчатые) массивы: Вместо двух циклов for использовать один foreach
Приветствую. В одном из курсов по программированию на C# есть тема про ступенчатые массивы. В...

Как использовать один запрос вместо двух?
В CMS есть различные типы внутренних объектов. У каждого объекта есть основные поля, общие для...

Связанный список - использовать в функции один указатель вместо двух
Возможно ли использовать в этой функции один указатель вместо двух (*cur и *prev) ? #include...

Вместо двух фреймов один
У меня такой вопрос, я хочу сделать что бы при нажатиии на ссылку фрейм загружался на место двух...

9
1452 / 845 / 150
Регистрация: 06.06.2012
Сообщений: 2,370
26.09.2012, 12:22 2
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void SaveScreen(Bitmap bitmap, string fileName, string datePath, EncoderParameters encParams)
        {
            try
            {
                if (bitmap == null || String.IsNullOrEmpty(fileName) || String.IsNullOrEmpty(datePath) || encParams == null) return;
 
                DirectoryInfo directoryInfo = new DirectoryInfo(datePath);
                if (!directoryInfo.Exists)
                    directoryInfo.Create();
 
                bitmap.Save(fileName, jgpEncoder, encParams);
            }
            catch (IOException ex)
            {
                //Не удалось создать директорию.
            }
            catch (Exception ex)
            {
                //Все остальные ошибки.
            }
            finally
            {
                if (bitmap != null)
                    bitmap.Dispose();
            }
        }
Добавлено через 16 минут
Цитата Сообщение от Tolias28 Посмотреть сообщение
Сделал я это по той причине, чтобы при каждом сохранении скрина не проверять существование папки (лишние операции с файловой системой ведь очень дорогостоящие по ресурсам)
Тебе лучше сделать некий класс который будет держать переменную типа DirectoryInfo и который будет создавать папку и знать есть она на диске или нет! Вот тогда будет самый минимальный расход ресурсов!

Вечером если смогу, то опишу механизм подробнее!
1
210 / 134 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
26.09.2012, 20:03  [ТС] 3
Вы сделали то, чего я как раз и избегал - ваш код проверяет существование директории каждый при создании скрина!
0
1452 / 845 / 150
Регистрация: 06.06.2012
Сообщений: 2,370
26.09.2012, 20:58 4
Цитата Сообщение от LeniumSoft Посмотреть сообщение
Тебе лучше сделать некий класс который будет держать переменную типа DirectoryInfo и который будет создавать папку и знать есть она на диске или нет! Вот тогда будет самый минимальный расход ресурсов!
Вечером если смогу, то опишу механизм подробнее!
Вот это отменяется! Ввиду того что я разобраля в работе свойства Exists.

Цитата Сообщение от Tolias28 Посмотреть сообщение
Вы сделали то, чего я как раз и избегал - ваш код проверяет существование директории каждый при создании скрина!
Теперь надо тебе рассказать что же происходит!

И так! Само свойство:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/// <summary>
    /// Получает значение, определяющее наличие каталога.
    /// </summary>
    /// 
    /// <returns>
    /// Значение true, если каталог существует; в противном случае — значение false.
    /// </returns>
    /// <filterpriority>1</filterpriority>
    public override bool Exists
    {
      [SecuritySafeCritical] get
      {
        try
        {
          if (this._dataInitialised == -1)
            this.Refresh();
          if (this._dataInitialised != 0)
            return false;
          else
            return this._data.fileAttributes != -1 && (this._data.fileAttributes & 16) != 0;
        }
        catch
        {
          return false;
        }
      }
    }
Если переменная _dataInitialized равна -1 вызывается метод Refresh.

Как же он работает:
C#
1
2
3
4
5
6
7
8
9
/// <summary>
    /// Обновляет состояние объекта.
    /// </summary>
    /// <exception cref="T:System.IO.IOException">Устройство, например дисковод, не готово. </exception><filterpriority>1</filterpriority>
    [SecuritySafeCritical]
    public void Refresh()
    {
      this._dataInitialised = File.FillAttributeInfo(this.FullPath, ref this._data, false, false);
    }
Присваивает нашей переменной значение выданное функцией FillAttributeInfo

Она довольно большая и выполняет много работы!

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
[SecurityCritical]
    internal static int FillAttributeInfo(string path, ref Win32Native.WIN32_FILE_ATTRIBUTE_DATA data, bool tryagain, bool returnErrorOnNotFound)
    {
      int num = 0;
      if (tryagain)
      {
        Win32Native.WIN32_FIND_DATA wiN32FindData = new Win32Native.WIN32_FIND_DATA();
        string fileName = path.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
        int newMode = Win32Native.SetErrorMode(1);
        try
        {
          bool flag = false;
          SafeFindHandle firstFile = Win32Native.FindFirstFile(fileName, wiN32FindData);
          try
          {
            if (firstFile.IsInvalid)
            {
              flag = true;
              num = Marshal.GetLastWin32Error();
              switch (num)
              {
                case 2:
                case 3:
                case 21:
                  if (!returnErrorOnNotFound)
                  {
                    num = 0;
                    data.fileAttributes = -1;
                    break;
                  }
                  else
                    break;
              }
              return num;
            }
          }
          finally
          {
            try
            {
              firstFile.Close();
            }
            catch
            {
              if (!flag)
                __Error.WinIOError();
            }
          }
        }
        finally
        {
          Win32Native.SetErrorMode(newMode);
        }
        data.PopulateFrom(wiN32FindData);
      }
      else
      {
        bool flag = false;
        int newMode = Win32Native.SetErrorMode(1);
        try
        {
          flag = Win32Native.GetFileAttributesEx(path, 0, ref data);
        }
        finally
        {
          Win32Native.SetErrorMode(newMode);
        }
        if (!flag)
        {
          num = Marshal.GetLastWin32Error();
          switch (num)
          {
            case 2:
            case 3:
            case 21:
              if (!returnErrorOnNotFound)
              {
                num = 0;
                data.fileAttributes = -1;
                break;
              }
              else
                break;
            default:
              return File.FillAttributeInfo(path, ref data, true, returnErrorOnNotFound);
          }
        }
      }
      return num;
    }
Но вернёмся к Exists.

Из него видно что он вызовет всё это чудо только первый раз. При следующих обращениях он нам просто будет выдавать то что получил первый раз. Соответственно тебе надо только DirectoryInfo вывести за метод и не инициализировать постоянно! Тоесть один раз его создал указав путь к папке и потом в своём методе проверяй свойство Exists.
1
210 / 134 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
26.09.2012, 22:48  [ТС] 5
LeniumSoft, спасибо за такой довольно развернутый исследовательский ответ

Не по теме:

Вы не против, если мы продолжим обсуждение по коду в личке или в другой теме на форуме? То, о чем мы сейчас уже начали обсуждать, никому из людей, использующих HideScreener, не особо нужно и интересно:)

0
1452 / 845 / 150
Регистрация: 06.06.2012
Сообщений: 2,370
26.09.2012, 23:07 6
Цитата Сообщение от Tolias28 Посмотреть сообщение
Вы не против, если мы продолжим обсуждение по коду в личке или в другой теме на форуме? То, о чем мы сейчас уже начали обсуждать, никому из людей, использующих HideScreener, не особо нужно и интересно

Не по теме:

:) Я не против!

0
210 / 134 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
26.09.2012, 23:31  [ТС] 7
Вынес обсуждение из этой темы. Думаю, модераторы не будут против)
Продолжу...

Согласно поданной вами информации посмотрим теперь на производительность моего первоначального метода и сравним его с вашим методом, предложенным в вот этом посте. Я первоначально использовал вот такой метод:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
        private void SaveScreen(Bitmap bitmap, string fileName, string datePath, EncoderParameters encParams)
        {
            while (true) //При нормальной работе без исключений этот цикл проходит только один раз
            {
                try
                {
                    bitmap.Save(fileName, jgpEncoder, encParams);
                    break; //Сохранение скрина прошло успешно. Выходим из цикла
                }
                catch (Exception ex)
                {
                    if (!Directory.Exists(datePath))//если исключение возникло по той причине, что не существовало папки для скринов
                    {
                        try
                        {
                            //тогда пробуем ее создать
                            Directory.CreateDirectory(datePath);
                        }
                        catch (Exception exep)
                        {
                            //не получилось создать папку, потому записываем в лог сообщение об ошибке и выходим из цикла так и не сохранив скрин...
                            Debugging.LogError(exep, "Folder for screens can't created: " + datePath);
                            break;
                        }
                    }
                    else
                    {
                        //произошла неизвестная ошибка сохранения скрина, потому записываем в лог сообщение об ошибке и выходим из цикла так и не сохранив скрин...
                        Debugging.LogError(ex, "Error saving screen in file " + fileName);
                        break;
                    }
                }
            }
            // метод SaveScreen() не вызывается, когда bitmap == null, потому в данном месте я проверку на null во второй раз опустил
            //еще.. Я не вызывал Dispose() в блоке finally выше по той причине, так как цикл while выполнится по второму кругу, если не существовало папки для кринов, чтобы сохранить скрин в только что созданную папку
            bitmap.Dispose();
        }
Вы мне предложили сделать вот так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void SaveScreen(Bitmap bitmap, string fileName, string datePath, EncoderParameters encParams)
        {
            try
            {
                if (DirectoryInfo.Exists)
                    directoryInfo.Create();
 
                bitmap.Save(fileName, jgpEncoder, encParams);
            }
            catch (IOException ex)
            {
                //Не удалось создать директорию.
            }
            catch (Exception ex)
            {
                //Все остальные ошибки.
            }
            finally
            {
                if (bitmap != null)
                    bitmap.Dispose();
            }
        }
Согласно той информации, которую вы навели о свойстве DirectoryInfo.Exists, вынесем код этого свойства прямо в вами предложенный метод, чтобы визуально можно было сравнить количество операций при вашем методе и при моем:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
        private void SaveScreen2(Bitmap bitmap, string fileName, string datePath, EncoderParameters encParams)
        {
            try
            {
                //вынесем свойство DirectoryInfo.Exists прямо сюда, сэмулировав его:
                bool PropertyExists;
                try
                {
                    if (this._dataInitialised == -1)
                        this.Refresh();
                    if (this._dataInitialised != 0)
                        PropertyExists = false;
                    else
                        PropertyExists = this._data.fileAttributes != -1 && (this._data.fileAttributes & 16) != 0;
                }
                catch
                {
                    PropertyExists = false;
                }
                //конец сэмулированного свойства DirectoryInfo.Exists
 
                if (PropertyExists)
                    directoryInfo.Create();
 
                bitmap.Save(fileName, jgpEncoder, encParams);
            }
            catch (IOException ex)
            {
                //Не удалось создать директорию.
            }
            catch (Exception ex)
            {
                //Все остальные ошибки.
            }
            finally
            {
                if (bitmap != null)
                    bitmap.Dispose();
            }
        }
И что мы видим? два блока try - один в другом. Вау! А мы то начинали разговор о том, как избежать вложенных блоков, вспоминаете? А результат то получился таким самым. Даже более, ваш метод получился не такой оптимальный как мой. В моем методе в 95% случаев работает только один блок try, так как в 95% случаев папка для скринов существует. И потому мой метод в 95% случаев исполняет только вот эти две строчки:
C#
1
2
3
4
5
6
7
8
9
try
                {
                    bitmap.Save(fileName, jgpEncoder, encParams);
                    break; //Сохранение скрина прошло успешно. Выходим из цикла
                }
                catch (Exception ex)
                {
                ......
                }
А вами предложенный метод кроме того, что исполняет строчку bitmap.Save(), также исполняет вот это:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//вынесем свойство DirectoryInfo.Exists прямо сюда, сэмулировав его:
                bool PropertyExists;
                try
                {
                    if (this._dataInitialised == -1)
                        this.Refresh();
                    if (this._dataInitialised != 0)
                        PropertyExists = false;
                    else
                        PropertyExists = this._data.fileAttributes != -1 && (this._data.fileAttributes & 16) != 0;
                }
                catch
                {
                    PropertyExists = false;
                }
                //конец сэмулированного свойства DirectoryInfo.Exists
 
                if (PropertyExists)
К тому же получились вложенные блоки try (в моем методе вложенные блоки только в catch, а они там вызываются очень редко). Мой итог: ваш совет не дал возможности уменьшить колиство влоежнных блоков try, к тому же в производительности ваш метод тоже проигрывает. Покажите, в чем я не прав
0
1452 / 845 / 150
Регистрация: 06.06.2012
Сообщений: 2,370
27.09.2012, 11:59 8
Ёлки палки! Про try catch мы говорили когда ты строку в bool парсил! Насчёт этого метода ты попросил показать как бы я его переписал! Я тебе его переписал более понятно и красиво! Без бесполезных зацикливаний и прочего! Причём тут вообще try catch? Этот код работает с файловой системой и его надо засунуть в try от греха! Я не пойму за какой производительностью ты гонишься? Эти оба метода отработают очень быстро и ты этого даже не заметишь! Сохрани в начале метода колличество текущих тиков и в конце метода отними от текущих тиков то значение которое ты получил вначале.

C#
1
2
3
4
5
long ticksCount = Environment.TickCount;
 
...
 
int milliseconds = TimeSpan.FromTicks(Environment.TickCount - ticksCount).Milliseconds;
В переменной milliseconds ты увидишь колличество милисекунд за которые отработал твой метод! И скорее всего это будет ноль или единица если сохраняемая картинка много весит!

Я то тебе представил более понятный и не запутанный метод! А работает он так же!
0
210 / 134 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
27.09.2012, 13:29  [ТС] 9
Вы меня неправильно поняли, а я вас... В результате получилось черт знает что Извините... Тогда проехали....

Добавлено через 25 минут
Я бываю иногда очень озабочен граммами производительности, даже если код от этого становится не такой красив.. но это наверное плохо?
0
1452 / 845 / 150
Регистрация: 06.06.2012
Сообщений: 2,370
27.09.2012, 20:18 10
Цитата Сообщение от Tolias28 Посмотреть сообщение
Я бываю иногда очень озабочен граммами производительности, даже если код от этого становится не такой красив.. но это наверное плохо?
Надо просто использовать это там где надо! Вот когда тебе надо будет сохранять по 500 картинок в секунду стоит заботится о каждом такте! А когда сохраняется картинка в 10 секунд можно и пограмотнее для себя писать! Ну а когда для других пишешь так надо вообще идеально!
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.09.2012, 20:18
Помогаю со студенческими работами здесь

Сделать вместо двух бордеров один
&lt;input placeholder=&quot;Логин&quot; name = 'login' type=&quot;text&quot; pattern=&quot;{2,64}&quot; required title=&quot;Разрешены...

Функция выводит один результат вместо двух
здравствуйте. функция должна выводить 2 переменных, но по факту выводит только одну ( первую...

Заменить один элемент строки вместо двух
Здравствуйте уважаемые форумчане. Столкнулся с такой проблемой: Есть...

Как использовать один Enum в двух проектах по связной ссылке?
Такая ситуация есть два проекта в одном решении, первый собирается в DLL, второй в EXE, в одном и...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru