Comments 24
Всё дело в том, что из-за определённых моментов, связанных с безопасностью, код, генерируемый Expression<...>.Compile() и код, который генерится при создании динамической билиотеки, может оказаться разным.
Далее, если продолжить рассуждения, то что такое ref struct в понятиях Span?Абзац, имхо, нечитабельный.
В целом, много технических особенностей реализации, но я честно так и не понял, зачем о них знать. Знать надо, когда и как применять Span, как он устроен, а не как он написан в недрах C#.
public delegate void Callback(Span span);
public unsafe void Invoke(Callback callback) {
Span s = stackalloc double[100];
callback(s);
}
В той же Java это сделано значительно элегантнее, и там заалоцировать массив на стеке задача JVM и escape analysis.
Span КМК сейчас это просто инструмент для создания АПИ доступных как из перформансного unsafe кода, так и для "обычного" safe кода. Ну, и дешевый способ создавать легковесные слайсы, без аллокаций на хипе. Пока не введут способ без unsafe кода и unsafe struct с fixed аллоцировать на стеке, это все равно игрушка для low level кода. Нужен высокоуровневый инструмент, для работы с массивами на стеке, в Java же он есть.
То есть в java нет возможности регулировать выделение в стеке вручную?
А как object можно зааллоцировать на стеке, если на уровне концепции языка практически нет стека?
Но тот же new Object() может заалоцировать объект хоть в хипе, хоть на стеке, хоть вообще по регистрам раскидать его.
www.beyondjava.net/escape-analysis-java
shipilev.net/jvm-anatomy-park/18-scalar-replacement
Вот это ваш прорыв в мире jvm?
dotnet делает это намного более предсказуемо и стабильно и делал это намного раньше чем появилось в java. Не думаю, что кто либо полагается на ваш new () аллокатор, который даже не может дать предсказуемого результата по выделении памяти в рамках метода. Как микрооптимизация, если сработало — ок, не сработало — сорри. Концептуально на проблемы работы с managed памятью это никак не повлияло — фрагментация, STW паузы и прочие прелести тормознутой managed платформы остались на месте.
Нет, там на уровне концепции языка нет стека практически. Java программа же не зависит от платформы, виртуальной машины итп.
В том то и дело, все дело в языке — если он не имеет апи для поддержки работы с памятью это ограниченность языка, комплилятора и рантайма — не более, а не ограничение наложенной кросплатформенной моделью разработки.
А что работа со стеком платформо зависимая штука или с памятью? Или по вашему программа написанная на С выделяет память на стеке по разному под виндой и линуксом?
Вообще-то, да.
Есть разные соглашения о вызовах функций.
Есть куча процессорных архитектур (x86, x64, ARM, ARM64), в т.ч. с экзотикой в виде little-endian/big-endian.
И Java скрывает все эти нюансы от программиста.
Посмотрите на кросс-платформенный C++ код — он кишит платформо-зависимыми ifdef-ами, которых в Java нет.
Все дело в языке — если он не имеет апи для поддержки работы с памятью это ограниченность языка, комплилятора и рантайма — не более.
Это ограниченность by design.
Дело не только в стеке, но и в возможности работать c native memory не задействуя механизмы CLR и значительно оптимизируясь механизмы выделения памяти, освобождения. в .net нам это апи переписаны многие стандартные net framework вещи — работа с сокетами, parsing api, работа с потоками(TPL) и т.д как результат интенсивные вычисления чувствительные к аллокациям даже из высокоуровневого api делают с производительностью native кода
https://www.codeproject.com/Articles/1223361/Benchmarking-NET-Core-SIMD-performance-vs-Intel-IS
Для Java это недосягаемые вершины на текущий момент.
Кстати можно почитать, что Java умеет делать с массивами на стеке без вмешательства девелопера?
Единственный способ, спрятать unsafe сейчас с помощью Span это коллбек, что довольно неуклюже.
public delegate void Callback(Span span);
public unsafe void Invoke(Callback callback) {
Span s = stackalloc double[100];
callback(s);
}
Еще можно вот так и в отлчии от Java аллокатора дает гарантировнный результат
static void Main(string[] args)
{
var array = "1,3,5,".AsSpan();
var separator = ",".AsSpan();
Span<int> span = stackalloc int[3];
int idx, parsed = 0;
while ((idx = array.IndexOf(separator)) != -1)
{
var val = int.Parse(array.Slice(0, idx));
array = array.Slice(idx + 1);
span[parsed++] = val;
}
var res = 0;
foreach (var i in span)
{
res += i;
}
Console.WriteLine(res);
Console.ReadLine();
}
unsafe не нужен при работе со стеком.
В шарпе изобрели слайсы? Привет, D!

Всегда слежу за новыми фичами c# и изучаю все по мере выхода. Когда появился Span, было сложно сходу понять что он делает, а времени эксперементировать самому как всегда нет) Прочитал много статей, но только после этой все понял и вопрос можно считать закрытым.
есть пару вопросов
1) пока читал статью ожидал упоминания ArraySegment и так его и не встретил. Видел использование этого класса в системных апи с сокетом, а в .net Core 1.x только они и были доступны — хотелось бы раскрытия вопроса, решает-ли Span проблемы которые решал ArraySegment, и что теперь использовать.
2) Поправьте меня если не прав — машина тьюринга описывает программирование на стеке, и куча не является необходимым элементом для создания тьюринг полных языков/программ, она существует чтобы было удобно строить абстракции. Глобальный вопрос состоит в том, возможно-ли использовать силу абстракции ООП и при этом остаться полностью на стеке, ну или хотя бы в той мере, чтобы куча не так сильно влияла на производительность. Самому пока чего-то не хватает чтобы разобраться.
[DotNetBook] Span: новый тип данных .NET