Как стать автором
Обновить
23
0.1
Денис @Hixon10

Бэкенд разработчик

Отправить сообщение
Вы пришли сюда получить ответ на вопрос или потролить? Если вам нужна модель памяти .NET, я не понимаю зачем вы расспрашивали про барьеры в async/await и давали ссылку на код Task.

ээ… Вы сослались на java в предыдущем вопросе. Я сослался на ответ и задал вопрос по вашему ответу. Мне просто не особо нравится, что все ссылаются на правило адекватности асинхронных примитивов, когда у нас нет первоисточника на это. Поэтому я испрашивал про конкретно те барьеры, которые решают обсуждаемые выше проблемы.

Барьеры памяти — глобальны. Поток, прочитавший из volatile поля, увидит все изменения, сделанные другим потоком до записи в любое volatile поле.

Все так. Вы хотите сказать, что в этом коде нет явных барьеров для до/после async/await, и мы просто пользуемся барьерами, которые ставятся для работы с состоянием Task?


По поводу же того какие изменения другие потоки гарантированно увидят — лично я пользуюсь следующим правилом, которое я называю правилом адекватности асинхронных примитивов:

Эти правила, что вы сказали, звучат адекватно, и все их копируют из раза в раз на stackoverflow. Проблема в том, что это нигде не сказано в официальной документации.


В случае Java у нас есть https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html. Есть ли что-то подобное у dotnet?

Ага, я вижу там большое количество volatile и тд. Но все случаи, что я вижу — относятся к работе к самому Task, или его состоянию. Выше же мы обсуждали барьеры для того, чтобы код в других потоках увидел изменения, сделанные внутри async/await, а также для того, чтобы новый код, запущенный через async/await, видел изменения, сделанные до его создания.

Не могли бы вы подсказать, где находится код, делающий это? С первого взгляда не вижу этого.


https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs

Как вы проверяете? Я вижу что строка изменяется и в случае private const string Content.
https://dotnetfiddle.net/mHRNKR

А зачем мы в этом способе выделяем новую строку (2), если мы уже поменяли исходную (1)?


    [Benchmark]
    public string Marshal_Span()
    {
        Span<char> chars = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(Content.AsSpan()), Content.Length);
        for (int i = 0; i < chars.Length; i++)
        {
            if (chars[i] == ' ')
            {
                chars[i] = ',';
            }
        }

        return Content; (1)
        return chars.ToString(); (2)
    }

|                                Method |        Mean |     Error |    StdDev | Allocated |
|-------------------------------------- |------------:|----------:|----------:|----------:|
|                               Replace |    55.15 ns |  0.110 ns |  0.102 ns |     824 B |
|                                  Join |   877.49 ns |  2.387 ns |  2.233 ns |    3480 B |
|                            Base_Regex | 2,107.93 ns |  2.620 ns |  2.323 ns |     936 B |
|                       Generated_Regex | 2,167.31 ns | 23.824 ns | 19.894 ns |     824 B |
|                     Сonstructor_Regex | 2,175.78 ns | 17.405 ns | 14.534 ns |     824 B |
|                        Char_NewString |   347.75 ns |  0.762 ns |  0.713 ns |    1648 B |
|                Char_NewString_FastFor |   345.49 ns |  0.764 ns |  0.677 ns |    1648 B |
|                        Span_NewString |   346.33 ns |  1.008 ns |  0.943 ns |    1648 B |
|                           Span_Concat | 1,503.21 ns |  1.903 ns |  1.687 ns |    2504 B |
|                           Char_Concat | 1,453.93 ns |  3.316 ns |  2.940 ns |    1680 B |
|         Unsafe_ReadOnlySpan_NewString |   297.68 ns |  0.470 ns |  0.416 ns |     824 B |
| Unsafe_ReadOnlySpan_NewString_Foreach |   308.40 ns |  1.223 ns |  1.144 ns |     824 B |
|                         Unsafe_String |   257.23 ns |  0.308 ns |  0.288 ns |         - |
|                 Unsafe_String_Foreach |   292.52 ns |  0.715 ns |  0.634 ns |         - |
|                          Marshal_Span |   257.43 ns |  0.517 ns |  0.484 ns |         - |
|                 Marshal_Span_ToString |   302.45 ns |  0.891 ns |  0.790 ns |     824 B |
|                Marshal_Span_NewString |   297.55 ns |  0.448 ns |  0.419 ns |     824 B |
|                         String_Create |   300.35 ns |  0.430 ns |  0.359 ns |     824 B |

создатель зио считает, что зио и лум должны существовать, где лум дает платформу, а зио — удобное, безопастное API поверх — https://www.youtube.com/watch?v=9I2xoQVzrhs

Примеры вот — https://stackoverflow.com/a/54413147/1756750, или https://stackoverflow.com/a/55139219/1756750


В целом, можно пробовать смотреть JIT ASM в условном https://sharplab.io/, но это не выглядит как надежный способ изучения вопроса, при условии что в sharplab даже Арма нет, где более слабые гарантии памяти. Еще можно в сорцы dotnet смотреть, но это про текущее состояние, а не спецификацию поведения.

А вот в ваших рукописных реализациях async/await ничего нет про барьеры памяти. Но они же иногда должны быть, иначе бы мы иногда не видели изменений, сделанных из асинхронного метода в методе, где мы ждем результат. Интересно, что и в официальных доках я тоже ничего про это не вижу, только в ответах на stackoverflow.

Возникает вопрос, зачем делать пул managed-объектов, вместо перехода на нативный аллокатор?

А кто-нибудь использовал такой подход в реальных проектах? А то например jemalloc.NET не особо обновляется в последние годы. В теории, даже API нужное есть в виде MemoryManager, надо только его реализовать.

Ага, я вот тоже не смог придумать, как поменять размер строки, при условии что нам еще и DWORD m_StringLength надо поменять.
Извиняюсь, не ясно спросил.

Я думал про какой-то такой пример:

string test = "Test"; 
Span<char> span = MemoryMarshal.CreateSpan(ref MemoryMarshal.GetReference(test.AsSpan()), test.Length); 
span[1] = span[3]; 
Console.WriteLine(test); // Ttst
        
Span<char> newSpan = span.Slice(0, 2);
Console.WriteLine(newSpan.ToString()); // Tt


То есть, мы получили span, который взят из оригинальной строки. Потом допустим хотим удалить последние 2 символа строки, условно говоря мой newSpan из кода выше. Сам по себе слайс ничего не сделает, просто выставит новые границы. Вот и было интересно, можно ли как-то в оригинальной строке, которую мы поменяли одним из небезопастных способов, потом еще и откусить суффикс, тем самым удалив несколько символов в конце.
Вопрос про второй способ (Span), ну, или вообще любой.

Допустим я получил из строки Span, поменял что-то, или вообще хочу взять слайс, потому что мне не нужны последние 2 символа. Если я вызову .ToString(), для того чтобы обратно получить строку, я получу в лоб аллокацию. Выглядит так, что весь смысл string -> span -> string потерялся.

[MethodImpl(MethodImplOptions.InternalCall)]
[DynamicDependency("Ctor(System.ReadOnlySpan{System.Char})")]
public extern String(ReadOnlySpan<char> value);

private static unsafe string Ctor(ReadOnlySpan<char> value)
{
    if (value.Length == 0)
        return Empty;

    string result = FastAllocateString(value.Length);
    Buffer.Memmove(ref result._firstChar, ref MemoryMarshal.GetReference(value), (uint)value.Length);
    return result;
}


Есть какой-то способ избежать аллокации тут, переиспользовав массив из оригинальной строки?
Единственная метрика, которой можно доверять — количество офферов в почтовом ящике :)
Вы не пробовали реализовать нечто подобное, что делает убер с автоматическим удалением фича тоглов?

github.com/uber/piranha
Было бы еще интересно послушать, зачем поступать в китайский университет на магистратуру? Какая после этого доступна траектория жизни? С таким требованием к английскому языку должно быть возможным поступить также либо в северную америку, либо в европу. Соответственно, у нас есть довольно много выбора.
А что спрашивают на сложных финтех интервью? Или под финтехом речь идёт про HFT, где идёт борьба за каждую нс?
Понял, спасибо.
Привет, спасибо за рассказ. Возникла пара вопросов:
  1. 4000 разработчиков в штате — пугающая цифра. Есть ли возможность немного описать разбиение людей по каким-то продуктам/группам? Или это не только Озон, но и какие-то другие проекты вашей фирмы?
  2. Платформенные команды забрали к себе все вкусные задачи, позволив продуктовым командам только разрабатывать бизнесовые фичи. Как вы боритесь с выгоранием людей в продуктовых командах, где нет никаких технологических челленджей, и нужно просто использовать готовые managed сервисы?

Информация

В рейтинге
2 981-й
Зарегистрирован
Активность