Публикации

KCEPOKC
насколько я знаю в баше можно потоково сжимать данные и сразу переправлять их по scp, как это сделать я конечно же не знаю 🥴
KCEPOKC
плюс data oriented design тоже можно полуркать чтобы не обосраться с перфом и не понимать почему
KCEPOKC
вот вроде неплохой видос как можно архитектуру в играх делать

KCEPOKC
но всё же чистая функциональщина разрушается об реальный мир где ты не можешь жить без стейта.

поэтому мультипарадигменные языки типа джавы и шарпа лучше.
KCEPOKC
я (немного) переобулся


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

терпите, джавики.

вот тебе, блять, 10 лет люди работали. жаль джава не умерла.
Комментарий отредактирован: 29 декабря 2024, 14:56
KCEPOKC
Щас попробовал у себя собрать на коленке бенчмарк по мотивам. стянул свежий бинарь JDK+valhalla и добавил туда JMH


package test;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.Random;
import java.util.concurrent.TimeUnit;


@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
@Fork(value = 1)
@Warmup(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 5000)
@Measurement(iterations = 5, timeUnit = TimeUnit.MILLISECONDS, time = 5000)
public class BenchValhalla {
    private Point[] mutablePoint;
    private ValuePoint[] valhallaPoint;

    @Setup
    public void setup() {
        var r = new Random(69);
        var samples = 5000;
        this.valhallaPoint = new ValuePoint[samples];
        this.mutablePoint = new Point[samples];

        for (int i = 0; i < valhallaPoint.length; i++) {
            valhallaPoint[i] = new ValuePoint(r.nextDouble(), r.nextDouble(), r.nextDouble(), r.nextDouble());
        }
        for (int i = 0; i < mutablePoint.length; i++) {
            var valh = valhallaPoint[i];
            mutablePoint[i] = new Point(valh.x, valh.y, valh.z, valh.w);
        }
    }

    @Benchmark
    public ValuePoint valhallaPoint() {
        var arr = valhallaPoint;
        var sum = new ValuePoint(0, 0, 0, 0);
        for (int i = 0; i < arr.length; ++i) {
            for (int j = 0; j < arr.length; ++j) {
                sum = sum.add(arr[j].sub(arr[i]));
            }
        }
        return sum;
    }

    @Benchmark
    public Point plainOldMutablePoint() {
        var arr = mutablePoint;
        var sum = new Point(0, 0, 0, 0);
        for (int i = 0; i < arr.length; ++i) {
            for (int j = 0; j < arr.length; ++j) {
                sum.mutableAdd(arr[j]);
                sum.mutableSub(arr[i]);
            }
        }
        return sum;
    }

    @Benchmark
    public Point plainOldImmutablePoint() {
        var arr = mutablePoint;
        var sum = new Point(0, 0, 0, 0);
        for (int i = 0; i < arr.length; ++i) {
            for (int j = 0; j < arr.length; ++j) {
                sum = sum.addImmutable(arr[j].subImmutable(arr[i]));
            }
        }
        return sum;
    }

    public static void main(String[] args) throws Exception {
        var options = new OptionsBuilder()
                .include(BenchValhalla.class.getSimpleName())
                .build();
        new Runner(options).run();
    }

    static value class ValuePoint {
        public final double x;
        public final double y;
        public final double z;
        public final double w;

        public ValuePoint(double x, double y, double z, double w) {
            this.x = x;
            this.y = y;
            this.z = z;
            this.w = w;
        }

        public ValuePoint add(ValuePoint p) {
            return new ValuePoint(x + p.x, y + p.y, z + p.z, w + p.w);
        }

        public ValuePoint sub(ValuePoint p) {
            return new ValuePoint(x - p.x, y - p.y, z - p.z, w - p.w);
        }
    }

    static class Point {
        public double x;
        public double y;
        public double z;
        public double w;

        public Point(double x, double y, double z, double w) {
            this.x = x;
            this.y = y;
            this.z = z;
            this.w = w;
        }

        public Point mutableAdd(Point p) {
            x += p.x; y += p.y; z += p.z; w += p.w;
            return this;
        }

        public Point mutableSub(Point p) {
            x -= p.x; y -= p.y; z -= p.z; w -= p.w;
            return this;
        }

        public Point addImmutable(Point p) {
            return new Point(x + p.x, y + p.y, z + p.z, w + p.w);
        }

        public Point subImmutable(Point p) {
            return new Point(x - p.x, y - p.y, z - p.z, w - p.w);
        }
    }
}


Результат по итогу вот такой:


Benchmark                             Mode  Cnt       Score      Error  Units
BenchValhalla.plainOldImmutablePoint  avgt    5  112872,954 � 7424,274  us/op
BenchValhalla.plainOldMutablePoint    avgt    5   37533,453 �  181,333  us/op
BenchValhalla.valhallaPoint           avgt    5   18884,832 �  554,865  us/op
Комментарий отредактирован: 29 декабря 2024, 14:50
KCEPOKC
мдамсики

чёто это не вяжется с тем что они на презентациях показывали))
KCEPOKC
А ещё стейт корутин можно сериализовать и таким макаром сделать сохранения игры.

Да, тож много думал про то как было бы прикольно их использовать. Например, что можно описать какой-нить игровой квест на await условий понятным линейным кодом.
KCEPOKC
а что если попробовать запустить на бете JDK с вальгаллой?

там норм валью тайпы есть
Комментарий отредактирован: 28 декабря 2024, 11:51
KCEPOKC
а если так


а вот с apple music айфремы не работают
Комментарий отредактирован: 29 ноября 2024, 19:06
KCEPOKC
можно айфремом



<iframe width="560" height="315" src="https://www.youtube.com/embed/tDPiLgmhUgE?si=W8ZMRyoBiskiRV-D" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
Комментарий отредактирован: 30 ноября 2024, 00:30 (2 раза)
KCEPOKC
По поводу перфа, можно инлайнить композицию, правда это не динамическая история вообще, нужно будет каждую комбинацию описывать. У меня на проекте я специально делал кодген чтобы заинлайнить массив в класс, типа делал абстрактный MyCoolArray и реализации MyCoolArray0, MyCoolArray1 и тп. Но была цель оптимизироваться по памяти в первую очередь. После 16ти элементов уже была реализация MyCoolArrayN с массивом честным.

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

Если совсем с ума сойти, можно ваще сделать «value types у нас дома» через VarHandle + byte[]. Производительность должна быть на уровне, тк JIT потом это всё вклеивает нормально.

конечно, это крайне костыльно, потому что JVM:(
Комментарий отредактирован: 29 ноября 2024, 14:46 (5 раз)
KCEPOKC
да я честно даже не знаю какие ещё скриптовые языки кроме вышеперечисленных есть хоть сколько-нибудь популярные.

Angelscript + C++ очень похож на groovy + java

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

мы же прикладные кодеры народ простой — нам джейсончик переложить и изредка литкод порешать.

а академической работой пусть занимаются учёные на грантах. а от изобретения до индустриального применения проходит какое-то время.

ну к примеру тот же paxos. очень сложный капец, поэтому придумали raft для решения задачек попроще.
KCEPOKC
да, даун, а что??

ну а чё он блицы свои сидит дёргает на дворе уже 2024век все норм ребята уже кодят на расте
KCEPOKC
Нуууу… смотря каким уровнем себя представляют.

Если человек называет себя сеньором но при этом не может атомарно работать с конкурентной мапой, а прод «не упал» только потому что ревьюер уже в сотый раз смог это заметить…

А по поводу второго, это зависит от задач. Я тут задушнил не спорю, потому что в 99% случаев тебе будет достаточно простого решения. но в случае где его недостаточно… из недавних примеров, замена EnumMap на ConcurrentHashMap просто чтобы «па-быстраму» сделать класс тред-сейф положила кластер. А вот это на ревью пролетело к сожалению.

По поводу третьего это прямо моя личная жопоболь, когда ты встречаешь в коде воздушный замок который какой-то челик построил сто лет назад. А тебе нужно там что-то поменять. По итогу проблема добавить одно поле в POJO превращается в путешествие туда и обратно только потому что кто-то до тебя решил что тут нужно байткодогенерацию зафигачить.

Сорри за оффтоп уже конкретный от сабжа.
Комментарий отредактирован: 27 ноября 2024, 19:23 (3 раза)
KCEPOKC
я вот скоко работаю (байесд, не спорю), от чего реально горела жопа и из-за чего людей увольняли:
1) неправильный канкаренси код
2) неэффективные структуры данных
3) решение выдуманных проблем
KCEPOKC
> начинаются извращения с венгерской нотацией типа long timeMs; double speedKmh

А минусы будут?
в джаве тем более это экономия аллокаций.

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

Опять же, имхо, настоящая проблема в ЯП это читаемость кода, а ещё важнее читаемость многопоточного и асинхронного кода. А вот эти все вещи типа «а какой иерархией типов и перегрузками мне выразить мою идеальную модель», за решением таких паззлов это к хаскеллу и прочим функциональщикам. Т.е. кодить не за деньги.

В реальной жизни ты:
1) чтобы не ошибиться в вычислениях тестируешь код
2) если тебе надо вычислить физ величину ты просто её вычисляешь. ты не думаешь.
Комментарий отредактирован: 23 ноября 2024, 18:05