Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
#Круги добра
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Я хочу получать рассылки с лучшими постами за неделю
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
Создавая аккаунт, я соглашаюсь с правилами Пикабу и даю согласие на обработку персональных данных.
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр Что спрятано в недрах Земли? Ад? Одному Аиду известно. А так же тем, кто пройдёт шахту до конца.

Эпичная Шахта

Мидкорные, Приключения, 3D

Играть

Топ прошлой недели

  • SpongeGod SpongeGod 1 пост
  • Uncleyogurt007 Uncleyogurt007 9 постов
  • ZaTaS ZaTaS 3 поста
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая кнопку «Подписаться на рассылку», я соглашаюсь с Правилами Пикабу и даю согласие на обработку персональных данных.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Директ Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня
0 просмотренных постов скрыто
5
Dedero
5 месяцев назад

Разбираем паттерны конкурентности⁠⁠

Разбираем паттерны конкурентности Программирование, Golang, Многопоточность, Backend, IT, Длиннопост

База

Параллельность - выполнение задач в один момент времени на разных логических ядрах.

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

Процессы:

  • Раздельная память

  • Раздельные ресурсы

  • Раздельные регистры

Потоки:

  • Общая память

  • Общие ресурсы

  • Раздельные стэк и регистры

Горутины:

  • Общая память

  • Общие ресурсы

  • Общий системный стэк

  • Общие регистры

Go runtime представляет модель P:M:G.

P - представляет логическое ядро процессора.

M - поток ОС по числу процессоров P.

G - структура, которая выполняет переданную функцию, создаётся по необходимости, минимум одна на старте программы (main). Стэк всего 2кб, может расширятся до 1гб для 64x и до 250кб для 32х систем.

Управление горутинами осуществляется планировщиком Go, а не ОС. Планировщик Go работает в пользовательском пространстве. Мы не можем напрямую управлять на каком процессоре будет исполняться горутина, за это отвечает планировщик.

Канал - очередь сообщений, которая умеет работать в многопоточной среде, работает по принципу FIFO.

Есть два типа каналов: буферизованный и небуферизованный.

Первый может хранить несколько сообщений, второй только одно.

Синхронизация

sync.WaitGroup - счётчик, который позволяет подождать завершения горутин.

sync.Mutex - блокирует доступ к ресурсу.

sync.RwMutex - разделяемая блокировка на чтение и запись. Читать могут несколько горутин, но мутировать данные только одна.

sync.Atomic - атомарная операция чтения и записи. Работает только с простыми значениями.

sync.Map - lock-free структура. Работает так же, как и обычная map, но потокобезопасная, можно использовать в многопоточной среде. Хорошо подходит для случаев, где надо много читать и мало писать. Если надо много писать, то лучше использовать обычную map и sync.RwMutex.

Небуферизованный канал

Разбираем паттерны конкурентности Программирование, Golang, Многопоточность, Backend, IT, Длиннопост

Буферизованный канал

Разбираем паттерны конкурентности Программирование, Golang, Многопоточность, Backend, IT, Длиннопост

Ограничения канала

Разбираем паттерны конкурентности Программирование, Golang, Многопоточность, Backend, IT, Длиннопост

Важные правила

  • Закрывает канал тот, кто в него пишет.

  • Если пишет несколько продюсеров, то закрывает тот, кто создал продюсеров.

  • Не закрытый канал держит ресурсы. Закрывать надо явно.

Паттерны

Generator

Микропаттерн, который наполняет канал. Закрываем канал, чтобы не было проблем.

func generator() <- chan int {

ch := make(chant int)

go func(){

for i := 0; i <= 12; i++ {

ch <- i + 1

}

close(ch)

}()

return ch

}

Wrapper

Оборачиваем функцию, добавляя функциональность. Если вам что-то говорит слово декоратор, то это тот самый паттерн.

func wrapper(wg *sync.WaitGroup, fn func()) {

wg.Add(1)

go func() {

defer wg.Done()

fmt.Println("Work before func")

fn()

time.Sleep(1 * time.Second)

fmt.Println("Work after func")

}()

}

func main() {

var wg sync.WaitGroup

wrapper(&wg, func() {

time.Sleep(1 * time.Second)

fmt.Println("heavy work")

})

wg.Wait()

}

Fan-in

Собирает результаты из нескольких каналов в один.

func fanIn(input1, input2 <-chan string) <-chan string {

ch := make(chan string)

go func(){

for {

select {

case s := <-input1: ch <- s

case s := <-input2: ch <- s

}

}

}()

return ch

}

Fan-out

Одна или несколько горутин пишут в канал, с другой стороны рабочие горутины читают канал, делают работу и умирают.

func worker(ch <-chan int, wg *sync.WaitGroup) {

wg.Done()

for v := range ch {

fmt.Println(v)

time.Sleep(1 * time.Second)

}

}

func sender() {

ch := make(chan int)

var wg sync.WaitGroup

for i := 0; i < 2; i++ {

wg.Add(1)

go worker(ch, &wg)

}

for i := 0; i < 10; i++ {

ch <- i

}

close(ch)

wg.Wait()

fmt.Println("done")

}

Pipeline

Данные обрабатываются цепочкой. Producer -> Producer/Consumer -> Consumer. Стадий обработки может быть сколько угодно.

func producer() <-chan int {

c := make(chan int)

go func() {

for i := 0; i <= 10; i++ {

c <- i + 1

}

close(c)

}()

return c

}

func producerConsumer(c <-chan int) <-chan int {

out := make(chan int)

go func() {

for v := range c {

out <- v * 2

}

close(out)

}()

return out

}

func consumer(ch <-chan int) {

for v := range ch {

fmt.Println(v)

}

}

Rate limiting

Хотя для rate limiter есть множество разных алгоритмов, рассмотрим один, основанный на тиках.

func ticker() {

ch := make(chan int, 5)

go func() {

for i := 0; i < 5; i++ {

ch <- i

}

close(ch)

}()

limiter := time.Tick(time.Second)

for v := range ch {

<-limiter // будем ждать секунду

fmt.Println(v)

}

}

Cancellation

Способ прерывания горутин. Необходим, чтобы избегать висящих горутин, останавливать слишком долгие операции.

1. WithCancel

func worker(ctx context.Context) {

for {

select {

case <-ctx.Done():

fmt.Println("Done")

return

default:

fmt.Println("Working...")

time.Sleep(500 * time.Millisecond)

}

}

}

func main() {

ctx, cancel := context.WithCancel(context.Background())

go worker(ctx)

time.Sleep(1 * time.Second) // работаем

cancel() // отменяем

time.Sleep(1 * time.Second) // время на завершение

}

2. WithTimeout

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) // спустя 2 секунды воркер перестанет работать

3. WithDeadline. Можно указать точное время остановки.

ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second)) // прибавляем к текущему времени две секунды

Worker Pool

Каждый воркер берёт задачу, делает работу и отправляет результат в канал, другая горутина, в нашем случае main, читает результат из канала.

func worker(jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {

defer wg.Done()

for j := range jobs {

time.Sleep(1 * time.Second)

fmt.Println("job", j)

results <- j * j

}

}

func main() {

jobs := make(chan int)

results := make(chan int)

var wg sync.WaitGroup

for i := 0; i < 3; i++ {

wg.Add(1)

go worker(jobs, results, &wg)

}

go func() {

for i := 0; i < 10; i++ {

jobs <- i

}

close(jobs)

}()

go func() {

wg.Wait()

close(results)

}()

for result := range results {

fmt.Println(result)

}

}

Actor model

Паттерн, при котором акторы общаются только через каналы, и меняют данные только через каналы.

type message struct {

amount int

response chan int

}

func counter(messages chan message) {

for m := range messages {

m.response <- m.amount + 1

close(m.response)

}

}

func main() {

messages := make(chan message)

var wg sync.WaitGroup

go counter(messages)

wg.Add(3)

for i := 0; i < 3; i++ {

go func(i int) {

defer wg.Done()

response := make(chan int)

messages <- message{amount: i, response: response}

fmt.Println(<-response)

}(i)

}

wg.Wait()

close(messages)

}

Это не все паттерны, их целая куча, но уже с этими можно делать интересные вещи, такие как балансировщики нагрузки, pub/sub системы, очереди задач, rate limiter и много всего другого.

Показать полностью 3
[моё] Программирование Golang Многопоточность Backend IT Длиннопост
3
0
neverending.cpp
neverending.cpp
9 месяцев назад
Лига программистов

Dead lock⁠⁠

Перед тем, как разобрать, что такое live lock, вспомним, что такое dead lock.

Deadlock bug на простейшем примере
Два потока захватывают мьютексы в разном порядке. Это может привести к ситуации, что планировщик запустит на выполнение поток 1, поток 1 захватит мьютекс 1, после чего планировщик приостановит выполнение потока 1 и запустит на выполнение поток 2. Поток 2 захватит мьютекс 2. Независимо от того, какой поток будет выполняться дальше, программа зависнет, т.к. потоки будут ждать разблокировки мьютексов (поток 1 - мьютека 2, поток 2 - мьютека 1), которая никогда не произойдет.

#include <iostream>
#include <thread>
#include <mutex>

void thread1(std::mutex& mutex1, std::mutex& mutex2)
{
std::lock_guard<std::mutex> lock1(mutex1);
std::cout << "Thread 1 acquired mutex1\n";

std::lock_guard<std::mutex> lock2(mutex2);
std::cout << "Thread 1 acquired mutex2\n";
}

void thread2(std::mutex& mutex1, std::mutex& mutex2)
{
std::lock_guard<std::mutex> lock2(mutex2);
std::cout << "Thread 2 acquired mutex2\n";

std::lock_guard<std::mutex> lock1(mutex1);
std::cout << "Thread 2 acquired mutex1\n";
}

int main()
{
std::mutex mutex1;
std::mutex mutex2;

std::thread t1(thread1, std::ref(mutex1), std::ref(mutex2));
std::thread t2(thread2, std::ref(mutex1), std::ref(mutex2));

t1.join();
t2.join();
}

Fix dead lock bug
В современном C++ баг, описанный выше, исправляется с помощью использования std::scoped_lock

#include <iostream>
#include <thread>
#include <mutex>

void thread1(std::mutex& mutex1, std::mutex& mutex2)
{
const std::scoped_lock lock(mutex1, mutex2);
std::cout << "Thread 1 acquired mutex1 and mutex2\n";
}

void thread2(std::mutex& mutex1, std::mutex& mutex2)
{
const std::scoped_lock lock(mutex1, mutex2);
std::cout << "Thread 2 acquired mutex1 and mutex2\n";
}

int main()
{
std::mutex mutex1;
std::mutex mutex2;

std::thread t1(thread1, std::ref(mutex1), std::ref(mutex2));
std::thread t2(thread2, std::ref(mutex1), std::ref(mutex2));

t1.join();
t2.join();
}

Больше технических постов тут t.me/neverending_cpp

Показать полностью
[моё] Кросспостинг Pikabu Publish Bot Текст C++ IT Многопоточность Deadlock
9
0
Mr.Ducks
Mr.Ducks
11 месяцев назад
Серия PHP и веб-разработка: полезные руководства и совет

Скрытые возможности управления памятью в высокоуровневых языках: секреты, которые знают немногие⁠⁠

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

Гайд: "Неизвестные фишки управления памятью в высокоуровневых языках"

1. Ленивые вычисления (Lazy Evaluation) в неожиданных местах

Некоторые языки, такие как Haskell или Python (с функцией generator), используют ленивые вычисления, когда результат не вычисляется, пока он не станет необходим. Однако это можно внедрить в повседневные задачи в других языках, таких как JavaScript или даже Java. Как использовать ленивые вычисления для оптимизации кода, который работает с большими массивами данных?

Пример для Python:

def lazy_range(n):

i = 0

while i < n:

yield i

i += 1

Где применить: Для задач, где ты работаешь с большими последовательностями данных, но хочешь минимизировать использование памяти.

Скрытые возможности управления памятью в высокоуровневых языках: секреты, которые знают немногие Многопоточность, Инженер, Станок, Промышленность, Длиннопост

2. Эффективное использование кэширования с WeakRef

Мало кто знает, что можно кэшировать объекты в памяти, но при этом освобождать память автоматически, если они больше не нужны. Это позволяет существенно снизить потребление памяти при работе с большими данными.

Python:

import weakref

class MyClass:

pass

obj = MyClass()

weak_obj = weakref.ref(obj)

Где применить: В местах, где требуется держать ссылки на объекты, но не перегружать память.

3. Аллокация памяти под многопоточность

В языках, как C++ и Rust, можно контролировать не только, как выделяется память, но и как она освобождается в многопоточном окружении. Даже в высокоуровневых языках, например, в Go или Kotlin, есть инструменты управления аллокацией памяти, о которых мало кто задумывается.

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

4. Принципы оптимизации памяти для асинхронного программирования

Асинхронность может вызвать утечку памяти, если неправильно управлять контекстами выполнения. Как избежать типичных ошибок в управлении памятью при использовании async/await в JavaScript или Python.

Где применить: Например, при работе с веб-серверами, обрабатывающими десятки тысяч запросов, важно управлять контекстами так, чтобы они не забивали память, особенно при медленных сетевых соединениях.

5. Функции с разбором мусора (Garbage Collection) в недокументированных языках

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

Инсайт: Тонкая настройка алгоритма Garbage Collection, оптимизированная под типы задач.

6. Контроль за аллокацией стека и кучи на уровне сборки

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

Где применить: В сложных многопоточных системах, где важна точная настройка производительности.

Важность:

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

Показать полностью 1
Многопоточность Инженер Станок Промышленность Длиннопост
0
30
Аноним
Аноним
2 года назад
Программирование на python

Делаю курс по многопоточному и асинхронному программированию на Python⁠⁠

Готова часть по многопоточке. Прошу дать обратную связь. Хотелось бы сделать курс максимально полезным и качественным.

https://stepik.org/course/172356/promo

[моё] Обратная связь Многопоточность Курс Текст
7
Аноним
Аноним
2 года назад
Лига программистов

Максимальное количество потоков Delphi⁠⁠

Здравствуйте!

Создаю задачи TTask в цикле. Всего должно быть 56, но создаются 23. Почему так может быть? При этом чем меньше кода в потоке, тем больше потоков удаётся создать. К примеру, если все потоки пустые и просто ждут (while true sleep...), то все создаются без проблем.

Вопрос Программирование Delphi Многопоточность Текст
18
1067
MikhailDubko
3 года назад
Наука | Научпоп

Геометрическое ядро САПР программ нового поколения⁠⁠

Для начала немного истории, все программы автоматизированного проектирования в том или ином виде берут свое начало с конца прошлого тысячелетия, а именно:

Autocad - 1982 г.

Revit - 1997 г.

Tekla - 1966 г.

Компас  - 1997 г.

Allplan - 1982 г.

ArchiCad - 1986 г.

Solidworks - 1993 г.

И многие иные, даже сложные комплексы для расчетов такие как ANSYS и ABAQUS созданы в конце прошлого столетия.

Из отечественных можно еще выделить Renga , но она создается на старом ядре C3D компании АСКОН, а они в свою очередь создатели Компаса, поэтому это одно и тоже решение в разных обёртках.


Все данные САПР программы объединены одним общим принципом, они все создавались на основе одного принципа обработки информации - последовательного, это было следствием реалий тех времён, не существовало аппаратных устройств многопоточной обработки информации. Но времена идут, всё меняется , но не меняются геометрические ядра. В среднем на создание полноценной САПР программы уходит от 5 до 7 лет и довольного большого числа сотрудников - разработчики, тестировщики, консультанты и т.д. и в текущих реалиях ни одна из компаний разработчиков не пойдет на полноценную перепись с нуля своих геометрических ядер под многопоточные CPU и GPU. Конечно, программы обновляются с каждым годом, но все данные нововведения по сути косметические без глубокой оптимизации.


В прошлом году я разместил пост в котором продемонстрировал возможности Unreal Engine 5 при отображении многомиллиардно полигональной геометрии. В течении последнего года я вел разработку геометрического ядра которое сможет использовать многопоточную обработку на CPU - процессов требующих двойной точности, а на GPU - процессов где хватает и одинарной точности. Новые видео карты Nvidia - 3070, 3080, 3090 уже способны находить решения с двойной точностью на тензорных ядрах (они используются при обработки трассировки лучей в играх)  , но на данный момент у меня работа с данными ядрами на этапе экспериментов.


По сути получилось решение которое по производительности превышает любую программу выше в списке от 10 до 100 раз и более. И это касается любых действий, отображение графики, копирования, изменений, перемещений, подсчета материалов и т.д.:

https://www.youtube.com/watch?v=cmcsxwrDo3o

В моем решение используется ровно такой же подход как в Unreal Engine 5 в технологии nanite. При удалении камеры пользователя происходит постепенная эрозия геометрии и упрощение геометрии вплоть до отображения одного пикселя, что позволяет отображать многократно больший объем информации по сравнению с программами "пенсионерами". Но у технологии Nanite есть один большой минус, необходимо предварительное кэширование шейдерных текстур на жёсткий диск , в САПР это невозможно , поэтому мне пришлось данную технологию переработать под САПР и особенно под армирование строительных конструкций и впереди еще много работы.

Показать полностью 1
[моё] САПР Bim Многопоточность Видео YouTube
95
7
demianimp
demianimp
3 года назад
Лига образования

Как Android УВЕЛИЧИВАЕТ RAM? | РАЗБОР⁠⁠

Как работает своп в Android-смартфонах? И почему он появился только сейчас, когда на ПК он был уже давно. Полезен ли он во флагманах или нужен для смартфонов среднего и доступного ценового сегментов? Разбираемся как Android увеличивает оперативную память и забирает её у накопителя!

СОДЕРЖАНИЕ

0:00 Вступление

0:53 Что такое своп?

2:19 Как работает ОЗУ в Android?

5:35 Недостатки свопа

6:35 Итоги

7:20 Полезно: Список своп-приложений

https://youtu.be/cQy1lki_VF4
Образование Учеба Обучение Операционная система Многопоточность Android iOS Windows Приложение Видео YouTube Оперативная память
0
8
demianimp
demianimp
3 года назад
Лига образования

Как работает многозадачность?⁠⁠

Сегодня настало время разобраться с тем, что такое многозадачность и как она работает на десктопных и мобильных операционных системах. Спойлер - как и человек - НЕ ОЧЕНЬ ТО!

Образование Учеба Обучение Операционная система Многопоточность Android iOS Windows Приложение Видео YouTube
2
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Директ Промокоды Отелло Промокоды Aroma Butik Промокоды Яндекс Путешествия Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии