Re[25]: Об эффективности программ
От: Pavel Dvorkin Россия  
Дата: 20.10.05 10:44
Оценка: -1 :)
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Pavel Dvorkin, Вы писали:


WH> StringBuilder sb = new StringBuilder();

WH>...
WH> for (int i = 0; i < 100000; ++i)
WH> {
WH> sb.Length = 0;
WH> sb.Append(szFirstName);
WH> sb.Append(szLastName);
WH> }
WH>[/c#]
WH>0,04493758

WH>Оптимизированый вариант на C# получается на уровне С++ Ну чуть медленнее.


Проверять не буду, приму на веру. Все верно, я так и ожидал. Только одно имей в виду — StringBuilder постоянно хранит и изменяет поле длины. И это не бесплатно. Ты уже заплатил за вычисление этой длины вот здесь

string szFirstName = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
string szLastName = "22222222222222222222222222222222222222222222222222222222222222222222222222222

(именно здесь, может, и нет, так как строки константые, но в других случаях — да)

Естественно, когда мы миллион раз одни и те же строки сцепляем, это не надо миллилн раз делать. А вот если строки все время разные, то вычисление их длины входит в плату за конкатенацию.

WH>Кстати для корректности теста перепиши свои на wchar_t.


А зачем ? Надо будет — перепишу. А пока мне и так хорошо — там, как я знаю, только 0-127. И незачем мне делать 50% оверхед. Я могу и не переписывать. А вот ты можешь на ASCII переписать ?
With best regards
Pavel Dvorkin
Re[26]: Об эффективности программ
От: Дарней Россия  
Дата: 20.10.05 10:53
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Батенька, вы бы хоть читали внимательно. Я и писал-то, что strcat медленнее.


вот я и читал твои высказывания о том, что на твою программу накладывались жесткие ограничения по времени работы, из-за чего ты использовал в своем коде небезопасные конструкции

небольшой эксперимент показал, что лишенный проблем с безопасностью вариант с использованием std::string еще и работает куда быстрее, чем твой вариант — ценой потери небольшого количества памяти из тех гигабайтов, которые были у тебя в наличии, но которые ты не использовал
Вот мне и стало интересно — чего ты в конце концов хотел добиться своими "оптимизациями"?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[30]: Об эффективности программ
От: GlebZ Россия  
Дата: 20.10.05 10:54
Оценка: +1
Здравствуйте, alexeiz, Вы писали:

GZ>>Другой вопрос в Net с одним и тем же буфером создавать две строки нельзя. Поэтому аналогичным будет создание всегда новой строки.

A>В этом тесте используется конкретная возможность C — создание строк на стеке с прямой целью, чтобы показать приемущество этого языка по сравнению с C#.
Да нет тут никакого преимущества. Преимущество имеет значительно более большее значение чем просто производительность. Про один буфер я прогнал. Можно и в одном буфере с помощью unsafe кода. Только использование unsafe дает большую производительность для конкретной задачи, но меньшую эффективность. Потому как нафигарить можно не хуже чем в C++.
Во вторых — это не создание строк, а заполнение буфера строками в цикле. Разница в этих терминах есть и существенная.
В третьих, если ты не получал ошибок когда ты выходишь за границы массива, значит ты никогда не писал на C. Так что данное упражнение отнюдь не показывает эффективность языка. Оно больше показывает его недостатки.

С уважением, Gleb.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Об эффективности программ
От: _Winnie Россия C++.freerun
Дата: 20.10.05 11:08
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

>Разумеется, эффективности внимание перестали уделять не везде. Для тех

>программ, которые и сейчас работают на пределе возможностей машины, за
>эффективность по-прежнему борются, да еще как, иначе ведь работать вообще
>не будет. Ну а там, где для предела далеко — чего это мы будем лишний
>десяток Мбайт экономить ? Пусть пользователь память докупит, она нынче
>дешевая!

Переходи в gamedev, и будет тебе счастье...
Правильно работающая программа — просто частный случай Undefined Behavior
Re[26]: Об эффективности программ
От: WolfHound  
Дата: 20.10.05 11:21
Оценка: +1
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Проверять не буду, приму на веру. Все верно, я так и ожидал. Только одно имей в виду — StringBuilder постоянно хранит и изменяет поле длины. И это не бесплатно. Ты уже заплатил за вычисление этой длины вот здесь

По сравнению с копированием строк особенно если строки длинные это ничтожные затраты времени.
А если случится промах кеша то...
... << RSDN@Home 1.1.4 beta 6a rev. 436>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[30]: Об эффективности программ
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.10.05 11:53
Оценка: +1
Здравствуйте, alexeiz, Вы писали:

A>Только с той разницей, что чтобы преобразовать буфер в строку в C, не нужно делать ничего. Например, нам надо передать строку после конкатенации в функцию foo(char*). В C — просто передаём этот самый буфер. В C# функция будет выглядеть как foo(string), и чтобы передать туда результирующую строку нам нужно сначала преобразовать StringBuffer в String.

Ты сильно преувеличиваешь стомость этой операции. Посмотри исходники StringBuilder.ToString() рефлектором.
З.Ы. Не все, что занимает меньше асм-команд, тратит меньше тактов
З.З.Ы. Не все вызовы одинаково дороги.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Об эффективности программ
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.10.05 11:53
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>А зачем ? Надо будет — перепишу. А пока мне и так хорошо — там, как я знаю, только 0-127. И незачем мне делать 50% оверхед. Я могу и не переписывать. А вот ты можешь на ASCII переписать ?

С некоторым извратом, но можем. Мы по-прежнему можем оперировать массивами байт (только, в отличие от плюсов, безопасно), и приводить их к строке только там, где нужно. Нет принципиальной проблемы завести пару классов CompactString/CompactStringBuilder. Они будут работать не слишком хуже стандартных аналогов. Но значительного выигрыша от этого не получится, по крайней мере до тех пор, пока мы не работаем с очень большими объемами.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[27]: Об эффективности программ
От: Pavel Dvorkin Россия  
Дата: 20.10.05 13:08
Оценка: -1
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Проверять не буду, приму на веру. Все верно, я так и ожидал. Только одно имей в виду — StringBuilder постоянно хранит и изменяет поле длины. И это не бесплатно. Ты уже заплатил за вычисление этой длины вот здесь

WH>По сравнению с копированием строк особенно если строки длинные это ничтожные затраты времени.

Нет, не ничтожные. На входе у тебя буфер из байтов или ushort. Строка, в сыром виде пришедшая, из файла, к примеру,. И длину ее найти можно только просмотрев символы в поисках некоего признака конца (0xD из файла). Это не копирование, но все же массовая операция. И делать ее у тебя кто-то будет, не ты сам, так кто-то из библиотеки. А вот я указатель на эту строку в memory-mapped файле возьму и дальше мое дело — искать ее длину или нет. Надо — найду. не надо — подожду пока что, может, и не понадобится.
With best regards
Pavel Dvorkin
Re[27]: Об эффективности программ
От: Pavel Dvorkin Россия  
Дата: 20.10.05 13:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>А зачем ? Надо будет — перепишу. А пока мне и так хорошо — там, как я знаю, только 0-127. И незачем мне делать 50% оверхед. Я могу и не переписывать. А вот ты можешь на ASCII переписать ?

S>С некоторым извратом, но можем. Мы по-прежнему можем оперировать массивами байт (только, в отличие от плюсов, безопасно), и приводить их к строке только там, где нужно. Нет принципиальной проблемы завести пару классов CompactString/CompactStringBuilder. Они будут работать не слишком хуже стандартных аналогов. Но значительного выигрыша от этого не получится, по крайней мере до тех пор, пока мы не работаем с очень большими объемами.

+1
With best regards
Pavel Dvorkin
Re[31]: Об эффективности программ
От: alexeiz  
Дата: 20.10.05 18:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, alexeiz, Вы писали:


A>>Только с той разницей, что чтобы преобразовать буфер в строку в C, не нужно делать ничего. Например, нам надо передать строку после конкатенации в функцию foo(char*). В C — просто передаём этот самый буфер. В C# функция будет выглядеть как foo(string), и чтобы передать туда результирующую строку нам нужно сначала преобразовать StringBuffer в String.

S>Ты сильно преувеличиваешь стомость этой операции. Посмотри исходники StringBuilder.ToString() рефлектором.

Я бы тебе посоветовал вставить эту операцию в тест и посмотреть на то, как увеличится время. Уверяю тебя, будет очень близко к простой конкатенации строк оператором сложения. Так что мы ничего не выигрываем применяя StringBuilder для конкатенации двух строк, что собственно абсолютно не удивительно.

S>З.Ы. Не все, что занимает меньше асм-команд, тратит меньше тактов

S>З.З.Ы. Не все вызовы одинаково дороги.
Re[31]: Об эффективности программ
От: alexeiz  
Дата: 20.10.05 18:31
Оценка:
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, alexeiz, Вы писали:


GZ>>>Другой вопрос в Net с одним и тем же буфером создавать две строки нельзя. Поэтому аналогичным будет создание всегда новой строки.

A>>В этом тесте используется конкретная возможность C — создание строк на стеке с прямой целью, чтобы показать приемущество этого языка по сравнению с C#.
GZ>Да нет тут никакого преимущества. Преимущество имеет значительно более большее значение чем просто производительность. Про один буфер я прогнал. Можно и в одном буфере с помощью unsafe кода. Только использование unsafe дает большую производительность для конкретной задачи, но меньшую эффективность. Потому как нафигарить можно не хуже чем в C++.
GZ>Во вторых — это не создание строк, а заполнение буфера строками в цикле. Разница в этих терминах есть и существенная.
GZ>В третьих, если ты не получал ошибок когда ты выходишь за границы массива, значит ты никогда не писал на C. Так что данное упражнение отнюдь не показывает эффективность языка. Оно больше показывает его недостатки.

Приемущество языка С заключается в том, что он позволяет (не требует а позволяет) спуститься на уровень железа. Для С# это очень и очень ограничено. Все размышления о выходе за границы массива идут лесом. Это просто отдельный разговор.
Re[27]: Об эффективности программ
От: Pavel Dvorkin Россия  
Дата: 21.10.05 05:44
Оценка: :)
Здравствуйте, Дарней, Вы писали:


Д>небольшой эксперимент показал, что лишенный проблем с безопасностью вариант с использованием std::string еще и работает куда быстрее, чем твой вариант — ценой потери небольшого количества памяти из тех гигабайтов, которые были у тебя в наличии, но которые ты не использовал

Д>Вот мне и стало интересно — чего ты в конце концов хотел добиться своими "оптимизациями"?

Ты бы хоть внимательно посмотрел, что ты со string сделал

std::string firstName = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
std::string lastName = "22222222222222222222222222222222222222222222222222222222222222222222222222222";
std::string astr = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
std::string bstr = "11111111111111111111111111111111111111111111111111111111111111111111111111111";

Это, между прочим, вызов конструктора. Который при этом вычисляет длину (поле string::_MySize) и теперь эта длина используется в операциях = и +=. А вызываешь этот конструктор ты один раз, а не 10000000 раз. Вот поставь так

        std::string res;
        for(size_t i=0;i<10000000;++i)
        {
        std::string firstName = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
        std::string lastName = "22222222222222222222222222222222222222222222222222222222222222222222222222222";
        std::string astr = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
        std::string bstr = "11111111111111111111111111111111111111111111111111111111111111111111111111111";

            res = firstName;
            res += lastName;
            res += astr;
            res += bstr;
        }


тогда и сравнивай.
Конечно, в этом случае и в моем коде надо сделать то же


char szTotal[500];
char * pszTmpTotal,*pszTmpFirst, *pszTmpLast;
for(size_t i=0;i<10000000;++i)
{
   char* szFirstName = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
   char* szLastName =  "22222222222222222222222222222222222222222222222222222222222222222222222222222";
   char* astr = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
   char* bstr = "11111111111111111111111111111111111111111111111111111111111111111111111111111";
   for(pszTmpTotal = szTotal,pszTmpFirst = szFirstName ; *pszTmpFirst;*pszTmpTotal++=*pszTmpFirst++); 
   for(pszTmpLast = szLastName; *pszTmpLast;*pszTmpTotal++=*pszTmpLast++); 
   for(pszTmpLast = astr; *pszTmpLast;*pszTmpTotal++=*pszTmpLast++); 
   for(pszTmpLast = bstr; *pszTmpLast;*pszTmpTotal++=*pszTmpLast++); 
   *pszTmpTotal = '\0';
}


только вот у меня будет в каждой из этих строчек одно-единственное присваивание указателю (szFirstName и т.д.), от длины строки вообще не зависящее, ну а у тебя массовая операция.

P.S. А вообще-то я придумал способ сделать еще быстрее. Примерно в 2 раза быстрее, чем мой вариант. Жаль, что в свое время до него не додумался.
Причем даже с нахождением длины, т.е. двухпроходный. Так что одна причина, почему я позволил себе потенциально небезопасный код, отпадает.. Вот только буфер все же придется оставить статическим — при попытке вставить в цикл выделение памяти и освобождение он проигрывает даже string. Так что полностью безопасным сделать все равно не удастся. Ну а кроме того, в реальной программе этот буфер жил очень долго, и строки в него добавлялись по мере надобности. И не только строки
With best regards
Pavel Dvorkin
Re[28]: Об эффективности программ
От: Дарней Россия  
Дата: 21.10.05 07:37
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Ты бы хоть внимательно посмотрел, что ты со string сделал

PD>Это, между прочим, вызов конструктора. Который при этом вычисляет длину (поле string::_MySize) и теперь эта длина используется в операциях = и +=. А вызываешь этот конструктор ты один раз, а не 10000000 раз. Вот поставь так

я прекрасно понимаю, что я сделал со string
длина каждой строки и должна вычисляться один-единственный раз, если тебя хоть сколько-то заботит производительность
точнее — там, где она считывается из источника.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[32]: Об эффективности программ
От: GlebZ Россия  
Дата: 21.10.05 09:54
Оценка: +1
Здравствуйте, alexeiz, Вы писали:

A>Приемущество языка С заключается в том, что он позволяет (не требует а позволяет) спуститься на уровень железа. Для С# это очень и очень ограничено. Все размышления о выходе за границы массива идут лесом. Это просто отдельный разговор.

Закон относительности. Можно повернуть и по другому. Преимущества C# то, что он не позволяет делать ошибки выхода за границы массива. Хотя и это неправда. Я прямо написал, что можно так делать, но это особый случай называемый unsafe кодом. Так что и C# умеет работать с памятью и указателями. Так что преимущества здесь нет.

С уважением, Gleb.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[33]: Об эффективности программ
От: alexeiz  
Дата: 21.10.05 10:26
Оценка: -2
Здравствуйте, GlebZ, Вы писали:

GZ>Здравствуйте, alexeiz, Вы писали:


A>>Приемущество языка С заключается в том, что он позволяет (не требует а позволяет) спуститься на уровень железа. Для С# это очень и очень ограничено. Все размышления о выходе за границы массива идут лесом. Это просто отдельный разговор.

GZ>Закон относительности. Можно повернуть и по другому. Преимущества C# то, что он не позволяет делать ошибки выхода за границы массива. Хотя и это неправда. Я прямо написал, что можно так делать, но это особый случай называемый unsafe кодом. Так что и C# умеет работать с памятью и указателями. Так что преимущества здесь нет.

Я посмотрю, как ты будешь со строками в unsafe коде работать. То, что ты можешь работать с памятью и указателями, для строк не имеет ни малейшего значения.
Re[34]: Об эффективности программ
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.10.05 10:31
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Я посмотрю, как ты будешь со строками в unsafe коде работать. То, что ты можешь работать с памятью и указателями, для строк не имеет ни малейшего значения.

Можно-можно. Никто не запретит ему в ансейф моде работать с байтами, и конвертить к строке от случая к случаю.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[32]: Об эффективности программ
От: GlebZ Россия  
Дата: 21.10.05 11:18
Оценка:
Здравствуйте, alexeiz, Вы писали:

S>>Ты сильно преувеличиваешь стомость этой операции. Посмотри исходники StringBuilder.ToString() рефлектором.


A>Я бы тебе посоветовал вставить эту операцию в тест и посмотреть на то, как увеличится время. Уверяю тебя, будет очень близко к простой конкатенации строк оператором сложения. Так что мы ничего не выигрываем применяя StringBuilder для конкатенации двух строк, что собственно абсолютно не удивительно.

Все зависит от того, как вставлять. StringBuilder.ToString — операция более интересная чем просто возврат буфера как стринг. Он будет возвращать только один раз. На второй вызов будет сгенерена другая строка. Это было введено в 1.1 как требование защиты. Как я уже говорил, строку можно изменять через unsafe. Можно туда нагенерить и очень плохой код(например переполнение стека для креша или взлома системы ). В старой версии при повторном ToString возвращалась ссылка на одну и ту же строку, и при ее изменении изменялись все связанные строки. Так что смотря как вставишь, и в какую версию Net Framework. А защищенный Framework мне кажется значительно лучше, чем беззащитный но быстрый.

С уважением, Gleb.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[34]: Об эффективности программ
От: GlebZ Россия  
Дата: 21.10.05 12:05
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Я посмотрю, как ты будешь со строками в unsafe коде работать.

Легко. Пишу примерно, возможны (или скорее всего будут) ошибки. Unsafe не часто пишешь.
//поскольку в севом варианте такое есть(непонятно зачем) то и здесь сделаю.
public static unsafe void SetLength(string s, int length)
{
    fixed(char *p = s)
    {
        int *pi = (int *)p;
        if (length<0 || length > pi[-2])
            throw( new ArgumentOutOfRangeException("Хоть какая-то защита :) ") );
        pi[-1] = length;
        p[length] = '\0';
    }
}
public static unsafe void Concat(string dest, string source1, string source2)
{
    int slen1=source1.Length;
        int slen2=source2.Length;
    SetLength(source1.Length, source2.Length);
    fixed(char* pSource1)
        {
      fixed(char* pSource2)
      {
              fixed(char* pDest)
                {
                  for(int i=0;i<source1.Length;i++)
                      pDesc[i]=*pSource1;
                  for(;i<source2.Length;i++)
                      pDesc[i]=*pSource2;
                }
      }            
        }
}
static usafe void MyProgram.Main()
{
const n=1000000;
string stringBuf=new String('\0', 100);
for(int i=0;i<n;i++)
  Concat(stringBuf, "bla", "bla-bla");
}


С уважением, Gleb.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[29]: Об эффективности программ
От: Pavel Dvorkin Россия  
Дата: 21.10.05 12:16
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Ты бы хоть внимательно посмотрел, что ты со string сделал

PD>>Это, между прочим, вызов конструктора. Который при этом вычисляет длину (поле string::_MySize) и теперь эта длина используется в операциях = и +=. А вызываешь этот конструктор ты один раз, а не 10000000 раз. Вот поставь так

Д>я прекрасно понимаю, что я сделал со string

Д>длина каждой строки и должна вычисляться один-единственный раз, если тебя хоть сколько-то заботит производительность
Д>точнее — там, где она считывается из источника.

А цикл, между прочим, выполняется 10000000 раз. Просто для того, чтобы время можно было замерить. А в реальной работе если он и выполнится 10000000 раз, то уж не с одними и теми же входными строками в любом случае Так что уж будь добр свой пример переделать таким образом, чтобы 10000000 он хотя бы имитировал, что строки у него новые.

Мне это — ничего не стоит


[code]
char szTotal[500];
char * pszTmpTotal,*pszTmpFirst, *pszTmpLast;
for(size_t i=0;i<10000000;++i)
{
char* szFirstName = куда надо 1
char* szLastName = куда надо 2
char* astr = куда надо 3
char* bstr = куда надо 4

// и во всех предыдущих 4 операциях скорость от того, что есть "куда надо i" не зависит и каждый раз эти "куда надо i" могут вполне быть различными. Или адресом одного и того же буфера, но содержащего другие данные

for(pszTmpTotal = szTotal,pszTmpFirst = szFirstName ; *pszTmpFirst;*pszTmpTotal++=*pszTmpFirst++);
for(pszTmpLast = szLastName; *pszTmpLast;*pszTmpTotal++=*pszTmpLast++);
for(pszTmpLast = astr; *pszTmpLast;*pszTmpTotal++=*pszTmpLast++);
for(pszTmpLast = bstr; *pszTmpLast;*pszTmpTotal++=*pszTmpLast++);
*pszTmpTotal = '\0';
}

Вот и ты так перепиши и попробуй скорость померить.
With best regards
Pavel Dvorkin
Re[33]: Об эффективности программ
От: Andrei N.Sobchuck Украина www.smalltalk.ru
Дата: 21.10.05 13:49
Оценка:
Здравствуйте, GlebZ, Вы писали:
GZ>В старой версии при повторном ToString возвращалась ссылка на одну и ту же строку, и при ее изменении изменялись все связанные строки

Фига се баг! Не ожидал.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Я ненавижу Hibernate
Автор: Andrei N.Sobchuck
Дата: 08.01.08
!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.