Pull to refresh
1
0
Send message

Ваши утверждения корректны только в случае, если вы работаете над проектом САМИ. А если людей много, то идёт забив, т.к. у каждого программиста своё понятие, что важно, а что нет. Можно, конечно, неугодных расстреливать, но так будет большая текучка кадров))

А для чего кроме кэша он ещё используется, по вашему?
Нормально работает только как key-database. Да, у него есть другие структуры, но из-за отсутствия транзакций, вы просто устанете реализовывать сложные flow (используя pipiline и compare-and-change подходы, можно, но нужно ли?).
Ещё есть расширение для time-series, но не знаю насколько это востребовано.
Может за последних 3 года ещё что-то появилось? С удовольствием послушаю.

НОРМАЛЬНЫМ людям вообще соц сети не нужны (с) (как же там природа, речка, и вообще "Не нужён нам этот ваш интернет")

Для НОРМАЛЬНЫХ есть одноклассники, там наверное точно политики нет. Можете там СВОБОДНО тусоваться и делиться котиками и фотографиями шашлыков ))

В Грузии же все слепые, не видят к чему подобный закон привел в России. Вышло на митинги не так и много (( Лет через 5-10 превратятся в Беларусь.

Если бы он его взломал без админских прав, тогда было бы интересно...

Придирки в сторону maven могу понять: gradle - это молодежно и модно. Правда если у вас старый комп, то под Идеей gradle подтормаживет, и раздражает своей паузой (между Ctrl-F9 и появлением какой-то индикации прогресса). И лично меня maven полностью устраивает для простых проектов (если не нужны кастомные самописные таски) - в gradle у вас полная свобода, в maven много ограничений. Рисовать свои плагины можно и там, и там.

Придирки в сторону Kotlin реально не понял? На java-платформе есть какая-то лучшая альтернатива?

А вы не пробовали посмотреть серию лекций противоположного направления? Говорят помогает...
Ладно ещё говорить о подделка первого полёта (типа не успевали), но их же было около 5-ти!!! Карл!!!

PS: Удивляюсь, когда вижу подобных людей на Хабре, но то что они всегда заминусованы говорит о вменяемости большинства аудитории Хабра, что всё-таки радует))

У автора в школе наверное 5 (то есть 12) по сочинению была. Вместо 100 слов написать 1000, это талант. У меня с этим проблемы были ))
Для курсовой, наверное, это неплохо, но для хабра не ок. Автор берегите своё и чужое время, не пишите ненужных буковок. Даже учебные мануалы не пишутся с расчётом на идиотов (если, конечно, это не гос организация).

Пишу из будущего, перечитав про посадки в 2017, 2018, 2022.
Наверное уже можно не радоваться )))

Он написан в точности таким, каким он был задуман, никакого вопроса про "не успевали" тут быть не может.

Если вы разработчик этого API и точно знаете, то я с вами соглашусь, а иначе это такое же голословное утверждение как и моё, ни чем неподтвержденное ))

то может быть это вопрос именно ваших ожиданий.

Этот инструмент имеет метод cancel, который просто не кенселит реальное выполнение.
Заявлять, что мои ожидания завышены - ну такое себе.
Если вы не читали мои другие коменты, то я напомню - я сердит, потому что видел проект написанный на этих CompletableFuture, и как его фиксать (добавить РЕАЛЬНЫЙ cancel) я не знал. Хорошо, что не пришлось..., просто забили на него :)).
Так что эта проблема человека читающего рекламу CompletableFuture в разных докладах и статьях, и не ищущего ложка дегтя в реальной документации, относится не только ко мне.

то может быть это вопрос именно ваших ожиданий.

Нормальное ожидание от метода cancel, что он будет отменять ВСЁ, включая ещё не выполненные задачи и ожидание результата. Иначе он должен называться по другому, например cancelWaiting/cancelResult. Возможно не стоило наследоваться от Future, дабы не нарушать ожидаемый контракт от предыдущей работы с Future.
Можно, конечно, ткнуть меня носом в javadoc "ATTEMPTS to cancel execution of this task. ... or could not be cancelled for SOME other reason". Повторюсь, считаю это или плохим дизайном, или bad naming.
Переотсылать разработчика на документацию к десяткам реализаций Future (особенно в старых проектах), чтобы понять реализуют они контракт или нет - такое себе.

Формально в споре (или в суде) вы победите, так как в документации на Future сказано: хотим отменяем, хотим - не отменяем :-) Это проблемы/обязанности девелопера читать внимательно документацию и/или сырцы. А понятие плохого/хорошего дизайна - это субъективно.

PS: Я надеюсь вы понимаете, что мы просто холиварим?

флаг Thread.currentThread().isInterrupted() в тру не ставится и InterruptedException

Это же только пол беды - вся цепочка продолжает выполнятся.
Для серьезных server-side проектов (с Circuit Barrier) это неприемлемо.

Это же и в документации сказано:

Извините, но это звучит это как оправдание "Ну да фигово я реализовал, НО в документации же в таком-то файле на такой-то строчке я об этом написал"

а есть идеи почему так сделано?

По срокам наверное не успевали. Сделать это КАЧЕСТВЕННО наверное нелегко. У той же RxJava уже несколько версий ПОЛНОГО переписывания было.
А если потом пофиксать - потеряешь совместимость.
Но открытый вопрос: если вы не реализовали БАЗОВОЙ функциональности по прерыванию цепочки (это не про InterruptedException), зачем вы развиваете этот API для улучшения возможности написания ДЛИННЫХ цепочек? хз :-)

свой статус операции намного универсальнее

Как по мне это может быть надежнее, если вдруг какая-то thirdparty функция (которую вы вызываете, и которая написана каким-то Васей) съест Thread Interrupted флаг, но точно не универсальнее.
Эта идея с флажком очень сильно пиарилась на ранних этапах разработки на Java, когда учебные книжки писались "экспертами" пришедшими из Си, и которые даже не знали (и не писали в своих книгах) как правильно обработать InterruptedException.
Не пишу свои флажочки уже более 10 лет, так как стандартный inerruption механизм прерывает блокирующие socket вызовы и тд, а свой/ваш флажочек - нет. Написание своего флажочка наверное имеет смысл, если вы не хотите держать ссылку на задачу/thread, но предпочитаете держать ссылку на свой флажочек... не вижу смысла в этом, всё равно какую-то ссылку вам придется держать.

Писатели этих статей, как вы уже запарили! :-)

Вы не правильно используете ООП.
ООП умер.
Что не так с ООП?
И бла-бла... Какая уже по счету статья?

Я не ищу эти статьи, они сами вылазят в рекомендациях.

Добавлю 5 копеек для следующих читающих ))
Если ld (ld-linux-x86-64.so) использовать вручную (для запуска приложений), то можно немного конфигурировать запуск (audit, lib path) (может быть полезно для "поиграться").
И также с ее помощью можно посмотреть список зависимостей/dll.

Достаточно написать FROM scratch в Dockerfile и мы получим абсолютно пустую файловую систему и сможем запустить свою программу без файлов вообще.

Есть у меня большие сомнения, что вы пробовали это сделать ))
А я попробовал - нужен как минимум линкер (без него docker жалуется, что ваш executable файл вообще не найден)
Если уже добавлен линкер, то тогда система будет уже вразумительно ругаться на отсуутсвующие dll-ки.

Вот пример моего минимального образа. Здесь minimal-hello - это c-шный hello-world собранный статически (вроде, судя по настройкам в Eclipse, но... мог здесь и налажать)

FROM scratch

ADD minimal-hello /

# linker
ADD sys_linux_root/lib64/ld-linux-x86-64.so.2 /lib64/

# Standard C lib
ADD sys_linux_root/usr/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/

CMD ["./minimal-hello"]

А вот немножко больший образ

FROM scratch

ADD minimal-hello /

# optional
ADD sys_linux_root/bin/* /bin/

#
# Required for ANY minimal executables
#  * dynamic linker
ADD sys_linux_root/lib64/ld-linux-x86-64.so.2 /lib64/

# Standard C lib
ADD sys_linux_root/usr/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/

# Additional libs fo ls/sh/bash
ADD sys_linux_root/usr/lib/x86_64-linux-gnu/* /usr/lib/x86_64-linux-gnu/

# Some data files
COPY hello.txt /
COPY hello.txt /hello-002.txt

CMD ["./minimal-hello"]

Содержимое моего sys_linux_root.
Здесь bash, cat, sleep, ls, sh просто, чтобы поиграться и дополнительные ddl-ки, нужные им или программам, которые делают хоть что-то полезное. Все эти файлы скопированы просто с моего текущего линукса.

.
├── bin
│   ├── bash
│   ├── cat
│   ├── ls
│   ├── sh
│   └── sleep
├── lib64
│   └── ld-linux-x86-64.so.2
└── usr
    └── lib
        └── x86_64-linux-gnu
            ├── libc.so.6
            ├── libdl.so.2
            ├── libpcre2-8.so.0
            ├── libpthread-2.31.so
            ├── libpthread.so
            ├── libpthread.so.0
            ├── libselinux.so.1
            └── libtinfo.so.6

Если кто-то умудрился сделать образ даже без линкера, то будет интересно послушать.

PS: Жду минусов, как обычно ))

Вот вам пример/эмуляция

fun testCompletableFutureCanceling(): Int {

val resultFuture = CompletableFuture.supplyAsync { println("task 1"); 1 }
    .thenApply { println("task 2"); it + 1 }
    .thenApply {
        var rr = it

        // to emulate unpredictable database workload
        val n = 8U // Random.Default.nextUInt(10U)
        println("N: $n")

        for (i in 0U..n) {

            // Emulation of long BLOCKING operation
            Thread.sleep(1000)

            println("Long task 3.$i => we request another portion of data from database using BLOCKING JPA call");
            rr++

            // probably our task is too long and we need to stop
            if (Thread.currentThread().isInterrupted) {

                // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                // Flag Thread.isInterrupted does NOT work there, but works properly if you use RXJava

                println("Seems the task is already canceled. We will cancel next steps.")
                throw IllegalStateException("Task is canceled.")
            }
        }

        println("Long task 3 => $rr")
        rr
    }
    .thenApply { println("task 4"); it + 1 }
    .thenApply { println("task 5"); it + 1 }
    .thenApply { println("task 6"); it + 1 }

return try { resultFuture.get(5, TimeUnit.SECONDS) }
       catch (ex: TimeoutException) {
           println("### Task works too long. We do not need it anymore. Lets cancel it.")

           // It does NOT work for CompletableFuture!!!
           resultFuture.cancel(true)

           -1
       }
       catch (ex: Exception) {
           println("### Task failed. Error: $ex")
           -1
       }

}

fun main() {
val message = testCompletableFutureCanceling()
println("Task is completed => result = $message")

// to make sure other thread are not interrupted
// (to emulate execution on server)
Thread.sleep(10_000)

}

Тестил сейчас на Java 17.

Output:

task 1
task 2
N: 8
Long task 3.0 => we request another portion of data from database using BLOCKING JPA call
Long task 3.1 => we request another portion of data from database using BLOCKING JPA call
Long task 3.2 => we request another portion of data from database using BLOCKING JPA call
Long task 3.3 => we request another portion of data from database using BLOCKING JPA call
### Task works too long. We do not need it anymore. Lets cancel it.
Task is completed => result = -1
Long task 3.4 => we request another portion of data from database using BLOCKING JPA call
Long task 3.5 => we request another portion of data from database using BLOCKING JPA call
Long task 3.6 => we request another portion of data from database using BLOCKING JPA call
Long task 3.7 => we request another portion of data from database using BLOCKING JPA call
Long task 3.8 => we request another portion of data from database using BLOCKING JPA call
Long task 3 => 11
task 4
task 5

Как видите после прерывания финальной CompletableFuture, все остальные продолжают выполняться (и даже task 4 и 5), потому что флаг cancel не передается по цепочке (и не "преобразуется" в Thread.isInterrupted()). А вот RXJava умеет нормально передавать флаг cancel (и прерывать) и перобразует его в Thread.isInterrupted() (что удобно в случае БЛОКИРУЮЩЕГО кода).

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

А здесь непонятный вообще output (почему вообще не закенселилось??? хз :-) ).
Если кто-то объснит, то буду благодарен

task 1
task 2
N: 8
Long task 3.0 => we request another portion of data from database using BLOCKING JPA call
Long task 3.1 => we request another portion of data from database using BLOCKING JPA call
Long task 3.2 => we request another portion of data from database using BLOCKING JPA call
Long task 3.3 => we request another portion of data from database using BLOCKING JPA call
Long task 3.4 => we request another portion of data from database using BLOCKING JPA call
Long task 3.5 => we request another portion of data from database using BLOCKING JPA call
Long task 3.6 => we request another portion of data from database using BLOCKING JPA call
Long task 3.7 => we request another portion of data from database using BLOCKING JPA call
Long task 3.8 => we request another portion of data from database using BLOCKING JPA call
Long task 3 => 11
task 4
task 5
task 6
Task is completed => result = 14

"это ошибка самого разработчика"

Да, вы абсолютно правы )) Разработчики не понимали изначально этой возможной проблемы, сделали проект (по приколу заюзав новые технологии, то ли наворотив свою ex-либу на основе CompletableFuture, то ли заюзав чью-то) и пошли дальше писать новые поекты, а проект потом свалился к кому-то на support... :-(

И я там ошибся в top-комменте - сервис получился подвержен не DDoS, а подвержен логической DoS (так будет правильнее, но не хочу править ориг коммент)


Может действительно сумбурно/непонятно изначально написал... но и так уже много буковок получилось.

"нюансы хорошо задокументированы"

Это если вы полезете в документацию )) А если вы просто почитаете вводные статьи, то там об этом может быть ничего и не сказано.
Например я давно знал о CompletableFuture, но об этом нюансе "хорошо" узнал (и запомнил) когда пытался ремонтировать тот проект.


PS: Интересно за что минусов накидали (всё же по делу и инфа полезная)? Ну фиг с ним ))

"похоже вы плохо разобрались в произошедшим."

Похоже вы не умеет читать внимательно, но минусовать умеете )).
Смотрите "содержащий blocked обращение к базе данных (посредством JPA/Hibernate)"!
Где здесь "реактивный драйвер базы"?

Подразумевалось, что используя Thread.currentThread().isInterrupted() в том проекте вы могли бы определить, что задача уже прервана и просто закончить ненужное уже выполнение (банально бросив Exception), а не делать уже ненужные новые запросы и нагружая систему, которая и так еле дышала. И это бы прекрасно сработало в случае RxJava, но невозможно в случае стандартного CompletableFuture.

"а просто так взять и что-то отменить это проблема, вы даже поток не можете остановить в произвольный момент"

Серьёзно? Не может быть!!! Вот это да, как неожиданно, просто глаза мне открыли!

Вы мне снова сладенький коммент подогнали )) Спасибки!

"Сосед А приходит к соседу Б и говорит, что у него слишком громко играет музыка, слышны крики, ругань, драки. "

Как вы "добровольно и осознано" пропагандистский штамп подхватили ))
А какой такой шум был у соседа Б в 2020-2021 году? Другие соседи ничего не слышали, даже наоборот очень тихие годы были.

"Вы так акцентируете внимание на слове "первый"."

Если мы пытаемся аппелировать к "человечности/справедливости", то не поверите - это очень важно. В тюряжку по закону садят именно "первого" (те напавшего).
Определенно с вас бы получился хороший адвокат, прочитали бы в суде лекцию про 1-й Большой Взрыв - и всё, победили бы на суде (как в американских фильмах).

Если мы уходим от терминов "человечности/справедливости", тогда "Кто сильней, тот и прав" и остальные рассуждения вообще не имеют смысла (США Ирак захватили по праву сильного ТОГДА, а сейчас уже ситуация другая (пожароопасная) и сил таких нет, приходится как-то с Йеменом бороться по другому).

На вашем примере, хорошо понятно почему владелец квартиры А не хочет просто заявить "Что его цель - захватить новую квартиру" (как это было бы пару веков назад и все бы кричали ура). Оказывается народ (кроме националистов и имперцев) не хочет чувствовать себя просто завоевателем, всё ему справедливые причины подавай, хоть убей: "Мы боремся с националистами/фаштстами/сатанистами!" "Мы освобождаем украинцев от националистического/фашистского правительства!" (ой, эта байка очень быстро устарела, уж слишком кринжовая была) "Мы боремся с трансформерами и ЛГБТ!" "Мы боремся с гендерно-нейтральными туалетами!" (самый последний писк моды :-), берите себе на вооружение). И казалось бы перебор уже с лозунгами/причинами/оправданиями, пованивает уже абсурдом, должны появится сомнения в адекватности... Но, глубинный "опытный" (с ваших слов) народ "добровольно и осознано" всё это хавает ))

Попробуйте откомпилировать

import java.util.EnumSet

inline fun <T, reified R : Enum> Iterable.mapToEnumSet(transform: (T) -> R): EnumSet =
mapTo(EnumSet.noneOf(R::class.java), transform)

fun Map<String, T>.test_mapToEnumSet(): Set =
this.entries.drop(5).map { it.value }.mapToEnumSet { it }

fun <T: Enum> Map<String, T>.test2_mapToEnumSet(): Set =
this.entries.drop(5).map { it.value }.mapToEnumSet { it }

inline fun <reified T: Enum> Map<String, T>.test3_mapToEnumSet(): Set =
this.entries.drop(5).map { it.value }.mapToEnumSet { it }

fun Map<String, T>.test_mapToSet(): Set =
this.entries.drop(5).map { it.value }.toSet()



Попытайтесь понять, что не так, почему не всё компилится... И, по крайней мере, вы ответите себе на вопрос почему компилятор (а точнее kotlin standard library) не может ВСЕГДА заменять HashMap на EnumMap. Возможно по похожей/этой причине он и не может ИНОГДА делать эту замену. Хотя скорее всего поскольку нельзя сделать замену ВСЕГДА автоматически, то не имеет смысла ее делать вообще.

PS: В котлине нет EnumMap/EnumSet, они есть только в джаве.

Есть одно маленькое жирное НО, по которому не следует использовать CompletableFuture - их невозможно РЕАЛЬНО отменить!!!

Из-за чего ваше ПО/service будет подвержена DDoS. Например у нас был какой-то сервис (написанный каким-то Васей), содержащий blocked обращение к базе данных (посредством JPA/Hibernate) и было наложено ограничение на макс ответ в 5 секунд... И чё-то начала БД подтормаживать (причины не помню), ответ от CompletableFuture просто отменили/проигнорировали и вернули ошибку... а запросы к базе и их комплексную обработку никто реально не отменил и в фоне оно продолжало работать, и жрать ресурсы CPU и БД... CompletableFuture cancel() просто не реализован и у вас нет возможности понять, что стоит остановиться... ((

Такой проблемы нет с RxJava (и наверное Spring Reactor, не помню проверял или нет), в RxJava отмена задача успешно распространяется и может быть проверена с помощью Thread.isInterrupted().

Проверял года 3 назад, может уже пофиксали, но сомневаюсь... Поэтому перед использованием CompletableFuture в реальном сложном проекте убедитесь, что cancel() работает, или используйте нормальные взрослые настраиваемые реактивные фреймворки.

Information

Rating
4,700-th
Registered
Activity

Specialization

Software Developer, Backend Developer
Java
SQL
Hibernate
Docker
Kotlin
RxJava 2
C++