Re[64]: Ну ты вообще многого не видишь... ;)
От: neFormal Россия  
Дата: 09.06.09 09:53
Оценка:
Здравствуйте, criosray, Вы писали:

F>>Фреймворк

F>>Библиотека
C>И? STL подходит 100% под определение фреймворка из приведенных Вами ссылок.

rofl

C>>>Не стоит выставлять на показ свои проблемы с логикой.

...coding for chaos...
Re[61]: Ну ты вообще многого не видишь... ;)
От: WFrag США  
Дата: 09.06.09 09:54
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

WF>>В типичных случаях он отдаёт наружу ровно ту строку, которую внутри себя редактирует. Естественно, с необходимой осторожностью, для гарантии неизменяемости этой отданной строки.


ГВ>То есть он отдаёт строку, держит на неё ссылку и при последующем, например, Append — дублирует её обратно во внутренний буфер?


Типа того. С учётом того, что внутренний буфер — это и есть эта строка (string на самом деле изменяема, внутри mscorlib).

ГВ>
ГВ>String s = strBuilder.ToString(); // Отдал строку
ГВ>strBuilder.Append("ABC"); // Вернул себе копию того, что было отдано через ToString и продолжил модификацию
ГВ>


ГВ>Так?


Что-то вроде того.
Re[62]: Ну ты вообще многого не видишь... ;)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 09.06.09 09:58
Оценка:
Здравствуйте, WFrag, Вы писали:

ГВ>>То есть он отдаёт строку, держит на неё ссылку и при последующем, например, Append — дублирует её обратно во внутренний буфер?

WF>Типа того. С учётом того, что внутренний буфер — это и есть эта строка (string на самом деле изменяема, внутри mscorlib).

ГВ>>
ГВ>>String s = strBuilder.ToString(); // Отдал строку
ГВ>>strBuilder.Append("ABC"); // Вернул себе копию того, что было отдано через ToString и продолжил модификацию
ГВ>>


ГВ>>Так?


WF>Что-то вроде того.


Тогда берём такой пример:

const int Count = 1000000;
String str = "Text";

StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10; ++i)
sb.Append("0123456789");
String s;

Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < Count; i++)
{
    s = sb.ToString();
}
stopwatch.Stop();
Console.WriteLine("Elapsed 1 {0}", stopwatch.Elapsed);

stopwatch.Reset();
stopwatch.Start();
for (int i = 0; i < Count; i++)
{
    s = sb.ToString();
    s = sb.ToString();
    s = sb.ToString();
    s = sb.ToString();
    s = sb.ToString();
}
stopwatch.Stop();
Console.WriteLine("Elapsed 5 {0}", stopwatch.Elapsed);


Если твоё предположение верно, то соотношение времен Elapsed1:Elapsed5 должно быть близко к 1:1. Прокрути тест, посмотри на результаты.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[65]: Ну ты вообще многого не видишь... ;)
От: criosray  
Дата: 09.06.09 10:00
Оценка:
Здравствуйте, neFormal, Вы писали:

F>>>Фреймворк

F>>>Библиотека
C>>И? STL подходит 100% под определение фреймворка из приведенных Вами ссылок.

F>rofl

F>

C>>>>Не стоит выставлять на показ свои проблемы с логикой.


У Вас соска выпала.
Re[59]: Ну ты вообще многого не видишь... ;)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.06.09 10:08
Оценка: 2 (1)
Здравствуйте, Геннадий Васильев, Вы писали:

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



ГВ>Как это, не будет копирования строки?


А говоришь код понятный.

public override string ToString()
{
    string stringValue = this.m_StringValue;
    .....................................
    stringValue.ClearPostNullChar();// добиваем пространство за Length + 1 нулями
    this.m_currentThread = IntPtr.Zero; // устанавливаем флаг на то что есть ссылка на строку
    return stringValue; // возвращаем ссылку на внутреннюю строку
}




public StringBuilder Append(string value)
{
    if (value != null)
    {
        string stringValue = this.m_StringValue;
        IntPtr currentThread = Thread.InternalGetCurrentThread();
        if (this.m_currentThread != currentThread) // Вот здесь если m_currentThread == IntPtr.Zero
        {                                          // Выделяется новая строка
            stringValue = string.GetStringForStringBuilder(stringValue, stringValue.Capacity);
        }
        int length = stringValue.Length;
        int requiredLength = length + value.Length;
        if (this.NeedsAllocation(stringValue, requiredLength))
        {// если места нехватает выделяется новая строка с новым капасити currentString.Capacity * 2;
            string newString = this.GetNewString(stringValue, requiredLength);
            newString.AppendInPlace(value, length);
            this.ReplaceString(currentThread, newString); 
        }
        else
        {
            stringValue.AppendInPlace(value, length);
            this.ReplaceString(currentThread, stringValue); // зписывается вместо старой
        }
    }
    return this;
}
и солнце б утром не вставало, когда бы не было меня
Re[66]: Ну ты вообще многого не видишь... ;)
От: neFormal Россия  
Дата: 09.06.09 10:10
Оценка:
Здравствуйте, criosray, Вы писали:

C>У Вас соска выпала.


крадёшь шутки у Петросяна?.
...coding for chaos...
Re[63]: Ну ты вообще многого не видишь... ;)
От: WFrag США  
Дата: 09.06.09 10:11
Оценка: 1 (1)
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Тогда берём такой пример:


ГВ>
ГВ>const int Count = 1000000;
ГВ>String str = "Text";

ГВ>StringBuilder sb = new StringBuilder();
ГВ>for(int i = 0; i < 10; ++i)
ГВ>sb.Append("0123456789");
ГВ>String s;

ГВ>Stopwatch stopwatch = new Stopwatch();
ГВ>stopwatch.Start();
ГВ>for (int i = 0; i < Count; i++)
ГВ>{
ГВ>    s = sb.ToString();
ГВ>}
ГВ>stopwatch.Stop();
ГВ>Console.WriteLine("Elapsed 1 {0}", stopwatch.Elapsed);

ГВ>stopwatch.Reset();
ГВ>stopwatch.Start();
ГВ>for (int i = 0; i < Count; i++)
ГВ>{
ГВ>    s = sb.ToString();
ГВ>    s = sb.ToString();
ГВ>    s = sb.ToString();
ГВ>    s = sb.ToString();
ГВ>    s = sb.ToString();
ГВ>}
ГВ>stopwatch.Stop();
ГВ>Console.WriteLine("Elapsed 5 {0}", stopwatch.Elapsed);
ГВ>


ГВ>Если твоё предположение верно, то соотношение времен Elapsed1:Elapsed5 должно быть близко к 1:1. Прокрути тест, посмотри на результаты.


Я не делаю предположений, я смотрю рефлектором. Но там не всё так прозрачно. Судя по коду, есть подозрение, что только первый .ToString не вызовет копирования.
Re[60]: Ну ты вообще многого не видишь... ;)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 09.06.09 10:13
Оценка:
Здравствуйте, Serginio1, Вы писали:

ГВ>>Как это, не будет копирования строки?

S>А говоришь код понятный.

И ты тоже прокрути тест из этого сообщения
Автор: Геннадий Васильев
Дата: 09.06.09
.

[skip code]

Это-то я всё понял, но за комментарии отдельное спасибо.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[60]: Ну ты вообще многого не видишь... ;)
От: WFrag США  
Дата: 09.06.09 10:14
Оценка:
Здравствуйте, Serginio1, Вы писали:

S>
S>    stringValue.ClearPostNullChar();// добиваем пространство за Length + 1 нулями
S>


Вот этот момент, кстати, непонятный. Судя по коду оно добивает 1 null, причём за null-терминатором строки (который, видимо, играет роль при взаимодействии с нейтивом), то есть это уже как бы второй unll. Но зачем?
Re[62]: Ну ты вообще многого не видишь... ;)
От: criosray  
Дата: 09.06.09 10:20
Оценка:
Здравствуйте, WFrag, Вы писали:

ГВ>>
ГВ>>String s = strBuilder.ToString(); // Отдал строку
ГВ>>strBuilder.Append("ABC"); // Вернул себе копию того, что было отдано через ToString и продолжил модификацию
ГВ>>


ГВ>>Так?


WF>Что-то вроде того.


Вовсе не типа того.

http://www.koders.com/csharp/fidB60F568A8CB6C4FE6DC7BC17ED5C0A52CA37E2F4.aspx?s=mdef%3Ainsert
Re[61]: Ну ты вообще многого не видишь... ;)
От: criosray  
Дата: 09.06.09 10:22
Оценка:
Здравствуйте, WFrag, Вы писали:


S>>
S>>    stringValue.ClearPostNullChar();// добиваем пространство за Length + 1 нулями
S>>


WF>Вот этот момент, кстати, непонятный. Судя по коду оно добивает 1 null, причём за null-терминатором строки (который, видимо, играет роль при взаимодействии с нейтивом), то есть это уже как бы второй unll. Но зачем?

И еще по теме:
http://blogs.gotdotnet.ru/personal/gaidar/PermaLink.aspx?guid=c2f3af10-950e-4d6e-9d14-d9a9cb0e71dc
Re[61]: Ну ты вообще многого не видишь... ;)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.06.09 10:28
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:


ГВ>Это-то я всё понял, но за комментарии отдельное спасибо.

А зачем же я коментарии то пишу?
Там есть такая запись после отдачи строки.

this.m_currentThread = IntPtr.Zero;



public override string ToString()
{
    string stringValue = this.m_StringValue;
    if (this.m_currentThread != Thread.InternalGetCurrentThread()) // Вот здесь если IntPtr.Zero идет копирование строки
    {                                                              
        return string.InternalCopy(stringValue);
    }
    if ((2 * stringValue.Length) < stringValue.ArrayLength)
    {
        return string.InternalCopy(stringValue);
    }
    stringValue.ClearPostNullChar();
    this.m_currentThread = IntPtr.Zero;
    return stringValue;
}
и солнце б утром не вставало, когда бы не было меня
Re[61]: Ну ты вообще многого не видишь... ;)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.06.09 10:30
Оценка:
Здравствуйте, WFrag, Вы писали:

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


S>>
S>>    stringValue.ClearPostNullChar();// добиваем пространство за Length + 1 нулями
S>>


WF>Вот этот момент, кстати, непонятный. Судя по коду оно добивает 1 null, причём за null-терминатором строки (который, видимо, играет роль при взаимодействии с нейтивом), то есть это уже как бы второй unll. Но зачем?

Это ты у них спроси. Она и так нуль терминированная. Какие то у них свои тараканы.
и солнце б утром не вставало, когда бы не было меня
Re[63]: Ну ты вообще многого не видишь... ;)
От: WFrag США  
Дата: 09.06.09 10:31
Оценка:
Здравствуйте, criosray, Вы писали:

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


ГВ>>>
ГВ>>>String s = strBuilder.ToString(); // Отдал строку
ГВ>>>strBuilder.Append("ABC"); // Вернул себе копию того, что было отдано через ToString и продолжил модификацию
ГВ>>>


ГВ>>>Так?


WF>>Что-то вроде того.


C>Вовсе не типа того.


С чем не согласен? Я смотрю по коду 2-ого фреймворка. Там, конечно, всё гораздо сложнее, но принцип вроде такой.

C>http://www.koders.com/csharp/fidB60F568A8CB6C4FE6DC7BC17ED5C0A52CA37E2F4.aspx?s=mdef%3Ainsert


Вообще это код из Mono. Кстати, они кешируют отданную строку в ToString, а настоящий фреймворк — нет.
Re[67]: Ну ты вообще многого не видишь... ;)
От: criosray  
Дата: 09.06.09 10:37
Оценка:
Здравствуйте, neFormal, Вы писали:

C>>У Вас соска выпала.


F>крадёшь шутки у Петросяна?.


А где Вы шутку увидели?
Re[64]: Ну ты вообще многого не видишь... ;)
От: criosray  
Дата: 09.06.09 11:03
Оценка:
Здравствуйте, WFrag, Вы писали:

WF>С чем не согласен? Я смотрю по коду 2-ого фреймворка. Там, конечно, всё гораздо сложнее, но принцип вроде такой.

C>>http://www.koders.com/csharp/fidB60F568A8CB6C4FE6DC7BC17ED5C0A52CA37E2F4.aspx?s=mdef%3Ainsert
WF>Вообще это код из Mono. Кстати, они кешируют отданную строку в ToString, а настоящий фреймворк — нет.

Принято. Согласен.
Re[64]: Ну ты вообще многого не видишь... ;)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 09.06.09 11:21
Оценка:
Здравствуйте, WFrag, Вы писали:

WF>Я не делаю предположений, я смотрю рефлектором. Но там не всё так прозрачно. Судя по коду, есть подозрение, что только первый .ToString не вызовет копирования.


А я всё больше таймеры обсчитываю. Вот тебе ещё один тест:

// Viva паранойя: разогрев StringBuilder:
for (int k = 0; k < 5; ++k)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 2; ++i)
        sb.Append("0123456789");
    String s = sb.ToString();
}

// Тест
const int Count = 10000000;
const int ConcatCount = 1;
const String StrConcat = "0123456789";
Stopwatch stopwatch = new Stopwatch();


stopwatch.Start();
for (int k = 0; k < Count; ++k)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < ConcatCount; ++i)
        sb.Append(StrConcat);
    String s = "A";
}
stopwatch.Stop();
TimeSpan tsCreate = stopwatch.Elapsed;
Console.WriteLine("Elapsed creation {0}", stopwatch.Elapsed);

stopwatch.Reset();
stopwatch.Start();
for (int k = 0; k < Count; ++k)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < ConcatCount; ++i)
        sb.Append(StrConcat);
    String s = sb.ToString();
}
stopwatch.Stop();
TimeSpan tsCreateAssign = stopwatch.Elapsed;
Console.WriteLine("Elapsed create+assign {0}", stopwatch.Elapsed);

stopwatch.Reset();
stopwatch.Start();
for (int k = 0; k < Count; ++k)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < ConcatCount; ++i)
        sb.Append(StrConcat);
    String s = sb.ToString();
    s = sb.ToString();
}
stopwatch.Stop();
TimeSpan tsCreateAssign2 = stopwatch.Elapsed;
Console.WriteLine("Elapsed create+assign2 {0}", stopwatch.Elapsed);

Console.WriteLine("EC:ECA ~=~ 1:{0}", tsCreateAssign.TotalMilliseconds / tsCreate.TotalMilliseconds);
Console.WriteLine("ECA:ECA2 ~=~ 1:{0}", tsCreateAssign2.TotalMilliseconds / tsCreate.TotalMilliseconds);

double dCAC = tsCreateAssign.TotalMilliseconds - tsCreate.TotalMilliseconds;
double dCA2CA = tsCreateAssign2.TotalMilliseconds - tsCreateAssign.TotalMilliseconds;

Console.WriteLine("ECA-EC = {0} ms (D1)", dCAC / Count);
Console.WriteLine("ECA2-ECA = {0} ms (D2)", dCA2CA / Count);
Console.WriteLine("D2:D1 = {0}:1", dCA2CA / dCAC);


Здесь сравнивается три длительности: создание строки (1), создание + одно присвоение ToString() (2), создание + два присвоения ToString() (3). Потом сравниваются две разницы: (2)-(1) = D1 и (3)-(2) = D2. Если StringBuilder оптимизирован под отдачу первой строки, то D2:D1 должно быть значительно больше, чем 2:1. В принципе, похоже, что так и есть — D2:D1 для десятисимвольной строки при ConcatCount=1 колеблется где-то в районе 3.5:1, то есть второй вызов sb.ToString() значительно медленнее первого. Но возможно, я чего-то не учитываю, например — активности GC.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[65]: Ошибка в примере:
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 09.06.09 11:25
Оценка:
Console.WriteLine("EC:ECA ~=~ 1:{0}", tsCreateAssign.TotalMilliseconds / tsCreate.TotalMilliseconds);
Console.WriteLine("ECA:ECA2 ~=~ 1:{0}", tsCreateAssign2.TotalMilliseconds / tsCreateAssign.TotalMilliseconds);


На итоговые выводы это не повлияло, но всё равно ошибка.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[62]: Ну ты вообще многого не видишь... ;)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 09.06.09 11:49
Оценка: +1
Здравствуйте, Serginio1, Вы писали:

ГВ>>Это-то я всё понял, но за комментарии отдельное спасибо.

S>А зачем же я коментарии то пишу?
S>Там есть такая запись после отдачи строки.

S>
S>this.m_currentThread = IntPtr.Zero; 
S>


Судя по всему, это просто маркер текущего потока, который модифицирует строку. Кстати, я не сообразил, что ты привёл код FW-шного стрингбилдера.

public override string ToString()
{
    /*
      this.m_currentThread - маркер "нахожусь в процессе модификации".
    */
    string stringValue = this.m_StringValue;
    if (this.m_currentThread != Thread.InternalGetCurrentThread()) // Вот здесь если IntPtr.Zero идет копирование строки
    {
      /*
        Это происходит в потоке, "чужом" по отношению к тому, который сейчас модифицирует строку.
        Другой случай - никто ничего не модифицирует, просто висит буфер с какими-то оставшимися данными.
      */
        return string.InternalCopy(stringValue);
    }
    if ((2 * stringValue.Length) < stringValue.ArrayLength)
    {
      /*
        А вот это - в том потоке, который сейчас занят модификацией.
        Если буфер заполнен меньше, чем на половину, то копируем строку.
        Маркер "продолжающейся модификации" при этом не снимается.
      */
        return string.InternalCopy(stringValue);
    }

    /*
      Если буфер заполнен больше, чем на половину, имеется активная модификация, и всё это происходит в потоке,
      осуществляющем эту модификацию, то считаем, что этим вызовом ToString текущая модификация заканчивается.
      Вот такая эвристика.
    */

    stringValue.ClearPostNullChar();
    this.m_currentThread = IntPtr.Zero;
    return stringValue;
}


ClearPostNullChar() вероятно, нужен для оптимизации по памяти.

В сумме, если это код FW-шного StringBuildera, то понятно, что он заточен на быструю отдачу строки при условии, что заполнено не менее половины буфера. То есть, EnsureCapacity(очень много) может привести к обратным результатам — StringBuilder будет считать, что всё ещё только начинается.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[63]: Ну ты вообще многого не видишь... ;)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 09.06.09 11:58
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:
Еще по умолчанию Capacity он же ArrayLength = 16,
Если строка меньше 8 то будет постоянно копироваться.
и солнце б утром не вставало, когда бы не было меня
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.