Задать вопрос
  • Может ли Раст полноценно заменить Джаву в сфере финансовых технологий?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Java
    Седой и строгий
    Нет. У них разные области применения. Java проектировалась именно как предельно простой и лёгкий для восприятия язык, максимально препятствующий выстрелу в ногу. Никогда этим параметрам не будет соответствовать язык одновременно пригодный к системному программированию. И это не учитывая тот фактор, что инвестиции в переписывание всего финтеха с Java на Rust потребуются больше, чем планетарный ВВП.
    Ответ написан
    4 комментария
  • Именование полей и таблиц(регистр)?

    rozhnev
    @rozhnev
    Fullstack programmer, DBA, медленно, дорого
    Без кавычек все имена в PostgreSQL приводятся к нижнему регистру, поэтому не советую использовать заглавные буквы в наименованиях
    Ответ написан
    Комментировать
  • Как передать из функции значения в разные потоки?

    bingo347
    @bingo347
    Crazy on performance...
    Начну с того, что код представленный автором в комментах к вопросу имеет deadlock между мьютексом и recv() из канала и завершается лишь по тому, что мы не ждем фоновые потоки. Вариант без deadlock будет выглядеть так:
    fn test() {
        let mut channels = Arc::new(Mutex::new(Vec::with_capacity(PAR)));
        let mut joins = Vec::with_capacity(PAR);
        for _ in 0..N / PAR {
            for _ in 0..PAR {
                let mut channels = Arc::clone(&channels);
                joins.push(thread::spawn(move || {
                    get(channels.lock().unwrap());
                }));
            }
        }
        for j in joins {
            j.join().unwrap();
        }
    }
    
    #[inline(always)]
    fn get(mut channels: MutexGuard<Vec<mpsc::Sender<i32>>>) -> i32 {
        let (tx, rx) = mpsc::channel();
        channels.push(tx);
        if channels.len() == PAR {
            exec(channels);
        } else {
            drop(channels); // drop гварда отпускает мьютекс
        }
        rx.recv().unwrap()
    }
    
    #[inline(always)]
    fn exec(mut channels: MutexGuard<Vec<mpsc::Sender<i32>>>) {
        let mut i = 0;
        for c in channels.iter() {
            i += 1;
            c.send(1).unwrap();
        }
        println!("{}", i);
        channels.clear();
        // а здесь гвард дропнется сам
    }

    Вторая проблема в том, что все потоки выполняются по сути по очереди, так как ждут разблокировки мьютекса от других потоков, из-за чего многопоточка тут не дает никаких преимуществ, а лишь создает накладные расходы. Ради эксперимента я попробовал заменить мьютекс на еще один канал:
    fn test() {
        let (tx, rx) = mpsc::channel::<mpsc::Sender<i32>>();
        let mut handles = Vec::with_capacity(N + 1);
        handles.push(thread::spawn(move || exec(rx)));
        for _ in 0..N {
            let tx = tx.clone();
            handles.push(thread::spawn(move || {
                get(tx);
            }))
        }
        drop(tx);
        for handle in handles {
            handle.join().unwrap();
        }
    }
    
    fn get(sender: mpsc::Sender<mpsc::Sender<i32>>) -> i32 {
        let (tx, rx) = mpsc::channel();
        sender.send(tx).unwrap();
        rx.recv().unwrap()
    }
    
    fn exec(receiver: mpsc::Receiver<mpsc::Sender<i32>>) {
        let mut channels = Vec::with_capacity(PAR);
        loop {
            for _ in 0..PAR {
                let Ok(tx) = receiver.recv() else {
                    return;
                };
                channels.push(tx);
            }
            let mut i = 0;
            for c in channels.iter() {
                i += 1;
                c.send(1).unwrap();
            }
            println!("{}", i);
            channels.clear();
        }
    }
    Но особо это профита не дает, так как основной пожиратель перфоманса - switch context в ОС. Тысячи потоков делают только хуже. Запускать потоков сильно больше чем есть ядер - это вообще плохая идея. Просто ради интереса переписал еще раз на асинхронных каналах tokio:
    async fn test() {
        let (tx, rx) = mpsc::unbounded_channel::<mpsc::UnboundedSender<i32>>();
        let mut handles = Vec::with_capacity(N + 1);
        handles.push(tokio::spawn(async move { exec(rx).await }));
        for _ in 0..N {
            let tx = tx.clone();
            handles.push(tokio::spawn(async move {
                get(tx).await;
            }))
        }
        drop(tx);
        for handle in handles {
            handle.await.unwrap();
        }
    }
    
    async fn get(sender: mpsc::UnboundedSender<mpsc::UnboundedSender<i32>>) -> i32 {
        let (tx, mut rx) = mpsc::unbounded_channel();
        sender.send(tx).unwrap();
        rx.recv().await.unwrap()
    }
    
    async fn exec(mut receiver: mpsc::UnboundedReceiver<mpsc::UnboundedSender<i32>>) {
        let mut channels = Vec::with_capacity(PAR);
        loop {
            for _ in 0..PAR {
                let Some(tx) = receiver.recv().await else {
                    return;
                };
                channels.push(tx);
            }
            let mut i = 0;
            for c in channels.iter() {
                i += 1;
                c.send(1).unwrap();
            }
            println!("{}", i);
            channels.clear();
        }
    }
    и запустил в многопоточном рантайме в дефолтной конфигурации (количество воркеров == количеству ядер), работает быстрее в 19 раз.

    P.S. без I/O операций асинхронщина тоже создает ненужные накладные расходы, я ее здесь использовал только из-за простоты переписывания, лучше взять обычный thread pool с синхронными тасками.
    Ответ написан
    Комментировать
  • Как правильно делать запросы в цикле?

    Maksclub
    @Maksclub Куратор тега PHP
    maksfedorov.ru
    it depends

    • если запросы зависимые, то в цикле
    • если запросы можно выполнить "параллельно", то можно асинхронно сделать сразу все 4 запроса и подождать самый медленный


    например через multi curl, тогда все 4 запроса будут выполняться за время самого медленного из них, а не за сумму времени, удобно через Guzzle Async

    $promise1 = $client->getAsync('http://www.example.com/foo1');
    $promise2 = $client->getAsync('http://www.example.com/foo2');
    $promise3 = $client->getAsync('http://www.example.com/foo3');
    $promises = [$promise1, $promise2, $promise3];
    
    $results = GuzzleHttp\Promise\settle($promises)->wait(); // тут все результаты


    в обоих случаях не понятно, зачем таймаут, тк синхронно второй запрос начнется только ПОСЛЕ выполнения предыдущего, а в асинхронном варианте они просто выполнятся "одновременно" и вы получите результат сразу от всех запросов... таймаут ни к селу ни к городу
    Ответ написан
    1 комментарий
  • Почему проблема с cors не исчезла?

    @falconandy
    В ошибке с фронта всё же написано - читайте внимательнее

    The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute
    Ответ написан
    Комментировать
  • Почему проблема с cors не исчезла?

    @calculator212
    Для cors лучше свои хендлеры писать, будет проще потом работать
    Ответ написан
    Комментировать
  • Почему в Docker собирается не тот Rust?

    bingo347
    @bingo347
    Crazy on performance...
    FROM rust:latest as build
    
    WORKDIR /test-tcp
    
    COPY ./Cargo.lock ./Cargo.lock
    COPY ./Cargo.toml ./Cargo.toml
    COPY ./src ./src
    
    RUN cargo build --release
    
    FROM debian:buster-slim
    
    COPY --from=build /test-tcp/target/release/test-tcp /usr/src/test-tcp
    
    CMD ["/usr/src/test-tcp"]

    Проблема в том, что в докере Вы создаете пустой проект из шаблона cargo
    RUN USER=root cargo new --bin test-tcp
    и компилируете его, потом копируете src
    Да, там есть еще один билд после этого, но я попробовал собрать Ваш Dockerfile у себя, и получил на втором билде результат инкрементальной сборки без изменений. То есть cargo не увидел, что папка src поменялась.
    Ответ написан
    4 комментария
  • Какую структуру таблиц выбрать для описания некоторой сущности, у представителей которой часть атрибутов совпадает, а часть - различна?

    ipatiev
    @ipatiev
    Потомок старинного рода Ипатьевых-Колотитьевых
    Как правильно написали выше, общепринятой практики нет.
    С натяжкой общепринятой можно назвать практику, когда часть свойств пишется в JSON поле, но как раз для описанного в вопросе случая она не должна применяться. Здесь однозначно подходит стандартная реляционная структура. Нет гарантии? Пишем null. Нет пробега? Пишем 0 км.

    А вот если нам надо хранить совсем различные товары, например автомобили и автомагнитолы, то специфические для товара характеристики можно писать в JSON поле. Но в этом случае потребуется отдельная база данных, которая будет хранить все возможные варианты ключей в этом JSON поле.
    Ответ написан
    2 комментария
  • Какую структуру таблиц выбрать для описания некоторой сущности, у представителей которой часть атрибутов совпадает, а часть - различна?

    hint000
    @hint000
    у админа три руки
    Как быть в этом случае? Создавать единую таблицу с кучей null или же несколько раздельных таблиц? Или делать таблицу для общих свойств и вспомогательные таблицы для дополнительных свойств? Может, есть некая общепринятая практика в этом случае?
    Нет чёткой общепринятой практики, потому что в разных случаях оптимальное решение может быть разное, в зависимости от постановки задачи.
    Иногда "единую таблицу с кучей null", иногда json, иногда EAV (не рекомендуется, но всё же лучше иметь возможность (знать о возможности), чем не иметь возможность): https://qna.habr.com/q/1224626
    У каждого варианта свои минусы и плюсы.

    Например, если "общих параметров" больше, чем "особых параметров", то куча null выглядит разумным выбором.
    Ответ написан
    1 комментарий
  • Как сделать много вставок в HashMap за минимальное время?

    vabka
    @vabka Куратор тега Rust
    Отвечая на твои вопросы:
    1 - есть ли что-то быстрее, чем tokio
    2 - правильно ли я использую tokio
    3 - насколько хорошая с точки зрения производительности идея использовать Arc
    4 - можно ли ускорить саму по себе структуру HashMap или только переписывать?


    1. В твоём случае лучше взять rayon для параллельной обработки, тк tokio предназначен для асинхронного io.
    2. см п1. Как именно ты tokio использовал я не смотрел. Дмитрий Беляев хорошо ответил по этому поводу
    3. Плохая. Лучше взять другую структуру данных
    4а. Можно процентов на 30 ускорить HashMap если заранее сделать with_capacity
    4б. И в n раз ускорить если сделать несколько HashMap по одному для каждого из N потоков (и передать во владение каждому потоку, чтобы не тратиться на синхронизацию и подсчёт ссылок).
    Для большого количества вставок неизвестного количества данных лучше подойдёт BTreeMap

    1. Многопоток тебе тут не поможет (а нет, обманул. Многопоток поможет. А вот async-нет)
    2. Ты бенчмаркаешь format!("{}", i)
    3. Вообще тебе тут стоит посмотреть на какие-нибудь concurrency-safe lockfree структуры. Например есть достаточно популярный крейт dashmap который такое предлагает.
    UPD: я обманул сам себя. dashmap не lockfree. Под капотом это как раз несколько HashMap, спрятанных за RwLock:
    pub struct DashMap

    pub struct DashMap<K, V, S = RandomState> {
        shift: usize,
        shards: Box<[RwLock<HashMap<K, V, S>>]>,
        hasher: S,
    }


    Мои бенчмарки с использованием criterion

    Результат:
    Обрати внимание, что тесты без format на порядок быстрее проходят.
    Но я не уверен, что корректно написал бенчмарк для btree_known_key__3M
    hashmap_no_capacity_format_key__3M
                            time:   [1.4810 s 1.5362 s 1.5952 s]
    
    hashmap_set_capacity_format_key__3M
                            time:   [1.0688 s 1.0744 s 1.0804 s]
    
    btree_format_key__3M    time:   [754.93 ms 843.10 ms 933.95 ms]
    
    
    vec_set_apacity__3M     time:   [1.7122 ms 1.7309 ms 1.7655 ms]
    
    dashmap_rayon_format_key__3M
                            time:   [294.76 ms 303.70 ms 316.85 ms]
    
    btree_known_key__3M     time:   [554.56 ms 556.18 ms 558.41 ms]


    Код

    use std::{
        collections::{BTreeMap, HashMap},
        time::Instant,
    };
    
    use criterion::{black_box, criterion_group, criterion_main, Criterion};
    
    fn hashmap_no_capacity_format_key(n: usize) -> HashMap<String, usize> {
        let mut map = HashMap::new();
        for i in 0..n {
            let key = format!("key_{i}");
            map.insert(key, i);
        }
        map
    }
    
    fn hashmap_set_capacity_format_key(n: usize) -> HashMap<String, usize> {
        let mut map = HashMap::with_capacity(n + 1);
        for i in 0..n {
            let key = format!("key_{i}");
            map.insert(key, i);
        }
        map
    }
    
    fn btreemap_format_key(n: usize) -> BTreeMap<String, usize> {
        let mut map = BTreeMap::new();
        for i in 0..n {
            let key = format!("key_{i}");
            map.insert(key, i);
        }
        map
    }
    fn vec_set_capacity(n: usize) -> Vec<usize> {
        let mut vector = Vec::with_capacity(n);
        for i in 0..n {
            vector.push(i);
        }
        vector
    }
    
    fn btreemap_known_key(keys: impl Iterator<Item = (String, usize)>) -> usize {
        let mut map = BTreeMap::new();
        for (k, v) in keys {
            map.insert(k, v);
        }
        map.len()
    }
    
    fn dashmap_rayon_format_key(n: usize) -> dashmap::DashMap<String, usize> {
        use rayon::prelude::*;
        let map = dashmap::DashMap::with_capacity(n);
        (0..n).into_par_iter().for_each(|i| {
            let key = format!("key_{i}");
            map.insert(key, i);
        });
        map
    }
    fn bench(c: &mut Criterion) {
        c.bench_function("hashmap_no_capacity_format_key__3M", |b| {
            b.iter(|| hashmap_no_capacity_format_key(black_box(3_000_000)))
        });
        c.bench_function("hashmap_set_capacity_format_key__3M", |b| {
            b.iter(|| hashmap_set_capacity_format_key(black_box(3_000_000)))
        });
        c.bench_function("btree_format_key__3M", |b| {
            b.iter(|| btreemap_format_key(black_box(3_000_000)))
        });
        c.bench_function("vec_set_apacity__3M", |b| {
            b.iter(|| vec_set_capacity(black_box(3_000_000)))
        });
        c.bench_function("dashmap_rayon_format_key__3M", |b| {
            b.iter(|| dashmap_rayon_format_key(black_box(3_000_000)))
        });
        c.bench_function("btree_known_key__3M", |b| {
            b.iter_custom(|times| {
                let mut total = vec![];
    
                for _ in 0..times {
                    let mut keys = Vec::with_capacity(3_000_000);
                    for i in 0..3_000_000 {
                        keys.push((format!("key_{i}"), i));
                    }
                    let start = Instant::now();
                    black_box(btreemap_known_key(black_box(keys.drain(..))));
                    total.push(start.elapsed());
                }
                total.iter().sum()
            });
        });
    }
    criterion_group! {
        name = benches;
        config = Criterion::default().sample_size(10);
        targets = bench
    }
    criterion_main!(benches);


    Ответ написан
    5 комментариев
  • Как переустановить Rust?

    vabka
    @vabka Куратор тега Rust
    У тебя нет никакой ошибки. Просто промотай консоль чуть ниже.
    То сообщение, которое тебе он вывел - он выводит всегда при запуске.
    Вот полный текст (я выделил курсором то, что ты прикрепил в вопросе):
    64a72702f13f6822200744.png
    Если у тебя по какой-то причине rustup закрывается и не даёт сделать выбор - передай ему все нужные параметры в аргументах:
    .\rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain stable --profile default


    Оригинальный ответ
    Вариант раз:
    1. Удали переменную окружения RUSTUP_HOME, CARGO_HOME и удали C:\Users\Eugene\.cargo\bin из PATH, да и саму папку .cargo тоже.
    2. Перезагрузи компьютер
    3. Снова запусти rustup

    Вариант два:
    Ещё можешь попробовать запустить rustup, предварительно выставив переменную среды RUSTUP_INIT_SKIP_EXISTENCE_CHECKS=yes
    Ответ написан
    8 комментариев
  • Как вывести только четные значения массива, не создавая новый массив?

    Alexandroppolus
    @Alexandroppolus
    кодир
    https://developer.mozilla.org/ru/docs/Web/JavaScri...

    если не хочешь создавать новый массив, то пройди forEach , в каждой итерации console.log если элемент подходящий
    Ответ написан
    Комментировать
  • Как заменить в массиве число нацело делящихся на 3 строкой "пропускам 3 "?

    liaFcipE
    @liaFcipE
    [1,2,3,6,4,12,3,8,15,55,54,4].map(v => v % 3 ? v : "skip 3")
    // (12) [1, 2, 'skip 3', 'skip 3', 4, 'skip 3', 'skip 3', 8, 'skip 3', 55, 'skip 3', 4]
    Ответ написан
    Комментировать
  • Что быстрее и меньше занимает памяти: dict или Redis?

    Вы сравниваете теплое с мягким.
    Dict - это внутренняя структура данных которая хранится только в рамках запущенной программы. И по этой причине доступ к данным внутри него будет быстрее, при одинаковом хранении. И при перезапуске все данный потеряются.
    Redis - это внешнее хранилище данных, при перезапуске программы данные не потрутся, но так как это внешнее хранилище то и доступ к данным будет медленнее.
    Но они решают разные задачи, и служат для разных целей
    Ответ написан
    3 комментария
  • Как сделать вот такой slider?

    delphinpro
    @delphinpro
    frontend developer
    Пишем кастомный слайдер. Нафиг не нужен здесь готовый.

    Все слайды размещаем "стопкой" с помощью грид-раскладки (можно абсолютом, но это хуже)
    Внутри слайда располагаемдва блока - текст и картинка. Текст невидимый, картинка за пределами слайда, в том сотоянии, из которого она будет выходит в состояние маленького размера справа. Блокам с текстом и картинкой задаем свойства плавного перехода (transition).
    Наверху "бутерброда" слой с кнопками управления.

    Дальше определяем три состояния картинки.

    Первое уже определено - это невидимый слайд, текст скрыт (opacity:0), картинка за пределами не видна.

    Второе состояние - "следующий слайд". Здесь текст все еще не виден, а картинка маленькая.

    Третье состояние - "активный слайд". Здесь текст виден и и картинка большая в центре.

    А дальше самое простое – по кликам на кнопки управления нужно просто менять состояния слайдов с помощью навешивания и убирания у них css классов.
    Ответ написан
    Комментировать
  • Как попасть в IT школьнику?

    @res2001
    Developer, ex-admin
    Если в твоем городе есть нормальный ВУЗ, то иди учись. Если нет, то стоит поискать куда ты можешь поехать учиться. У тебя сейчас единственная возможность в жизни получить бесплатное образование. Скорее всего такого подарка судьбы больше не будет никогда. Бывают, конечно, исключения.
    Обучение это не столько "новые технологии" программирования. Это еще и математика и прочие предметы, которые хорошо ставят мозги на место. Это то же нужно, если и не для программирования, то для собственного развития.
    Но самое главное, чему ты должен научиться в ВУЗе - учиться самостоятельно. Впрочем, похоже, это у тебя не плохо получается. Значит будешь оттачивать навык :-)
    Желаю удачи!
    Ответ написан
    5 комментариев
  • Как попасть в IT школьнику?

    xez
    @xez
    TL Junior Roo
    1. До 18ти лет, скорее всего, никуда не возьмут.
    2. В вашем возрасте обучение максимально быстрое и эффективное.

    Отсюда план:
    1. Учитесь, читайте книги, набивайте руку на пет-проектах. Читать и учиться придется на протяжении всей карьеры (спойлер, т.к. пенсии у вас не будет - всей жизни).
    2. Заканчивайте 11й класс.
    3. Постарайтесь поступить в ВУЗ (опционально).
    4. После первой сессии начинайте искать работу. К этому времени у вас должно скопиться небольшое портфолио проектов и опыт достаточный для трудоустройства на младшие позиции.
    5. Спокойно доучивайтесь в ВУЗ-е (опционально), паралельно работая.
    Ответ написан
    7 комментариев
  • Переходы на многостраничном сайте?

    Fragster
    @Fragster
    помогло? отметь решением!
    помимо варианта с бэкэндом есть еще генераторы статических сайтов, которые на основе шаблонов сгенерят папку для размещения на хостинге, и там можно в виде json положить "товары" и сгенерируется необходимое количество страниц. Например https://nuxtjs.org/docs/concepts/static-site-generation или https://vuepress.vuejs.org/
    Ответ написан
    Комментировать
  • Переходы на многостраничном сайте?

    Krasnodar_etc
    @Krasnodar_etc
    fundraiseup
    Ох, я постараюсь тезисно

    Вам нужен чуть более умный бэкенд (можно на любом языке, включая Node.js)
    Вместо html-файлов вы пишите шаблоны. Если у вас нода+Express.js, у него вроде был встроенный шаблонизатор ejs, есть ещё pug и много других (гуглить по Node шаблонизаторы). Если у вас на фронте React/Angular/View - лучше погуглить "название-библиотеки server side rendering", шаблонизация в них встроена

    Абстрактно, ваш бэкенд получает запрос, идёт в базу данных или какой-нибудь JSON-файл за данными, а потом передаёт эти данные в шаблонизатор

    В шаблонах можно использовать циклы, условия и разные другие плюшки из программирования. Вам не нужно писать 10 тэгов "a" для вывода списка, ваш список - стандартный массив, вы проходитесь по нему циклом и выводите данные в тэг "a". Условно:

    myItems.map(item => (
    <a href={item.link}>{item.text}</a>
    ))


    Нужно поменять что-то в ссылках - меняете в одном месте
    Нужно добавить товар или другие сущности - добавляете их данные в базу или JSON
    Ответ написан
    Комментировать
  • Генерация имени переменной из строки в пропсах?

    alexey-m-ukolov
    @alexey-m-ukolov Куратор тега JavaScript
    const images = {
      red: smoke1Red,
      blue: smoke1Blue,
      brown: smoke1Brown,
    }
    
    ...
    
    <img src={images[color] || smoke1Gray} />
    Ответ написан
    1 комментарий