Обновить
89
0
Сергей Шашков@ShashkovS

Менеджер продукта, методист, разработчик

Отправить сообщение
Если использовать двухшаговую сборку, то и продакш-контейнеры будут не такими тяжёлыми, и сборка с кешем будет практически мгновенной.
Но это если у вас не слишком много разной тяжести в духе pandas'а и т.п.

Я использую вот такое для вебсервиса на sanic, в котором используются допом aiohttp, asyncpg, honeybadger, Jinja2, Pillow. Если pillow не нужен, то, например, jpeg-dev будет не нужен, контейнер будет меньше.

FROM python:3.7.5-alpine3.10 as base

FROM base as builder
RUN mkdir /install
WORKDIR /install
RUN apk add --no-cache python3-dev \
                       build-base \
                       libc6-compat \
                       libffi-dev \
                       zlib-dev \
                       jpeg-dev \
                       linux-headers
RUN pip3 install --upgrade pip
COPY requirements.txt ./
RUN pip3 install --prefix=/install -r requirements.txt

FROM base
RUN apk add --no-cache bash jpeg-dev && \
    rm -r /tmp
EXPOSE 80
WORKDIR my_awesome_app
COPY --from=builder /install /usr/local
COPY my_awesome_app ./
RUN pip3 freeze
CMD ["python3", "app.py"]

Продакшн-контейнер получается 160MB.

Собрать мой стек на ubuntu/debian за быстро не получилось, поэтому, увы, без сравнения.
image
Неправильно написал. UI не блокирует. Не даёт ничего открыть (даже если знаешь точный путь) или сменить текущую папку на другую, пока не подождёшь минутку-другую. Окно можно закрыть и открыть заново, но снова придётся ждать.
например, мы создали и задействовали стандартный механизм асинхронной обработки событий от файловой системы


А вот скажите, это у одного меня такая проблема, или это общее:
иногда я хочу открыть какой-нибудь проект или файл. Для этого открывается кастомное IntelliJ-окно со структурой папок-файлов. Но оно открывается несколько минут. И даже если я в точности знаю путь к файлу, или тупо передумал, оно блокирует UI и пару минут что-то сканирует. Да, у меня там папка с проектами и там фигова туча подпапок и файлов. Но не надо туда внутрь лезть до того, как явно попросят.
Могу гифку сделать.
Уж не знаю, что они делают в фортране, но в питоне они обе валидные и тоже означают принципиально разные вещи.
Ну, RPG версии 7.2, на которую у вас ссылка, не чета тому RPG, который был в 1990-х.
Кода на RPG как раз примерно 1990-х годов я прочитал довольно много, и даже более древнего. ИМХО, не самый плохой язык для своего времени. Для меня он был понятнее ассемблера.
А RPG текущий — так вообще хорош для своих задач (специфичен правда. И стандартная библиотека совсем убога). Я на нём чего только не написал за 8 лет работы.
Дело в том, что тепло можно превращать в электроэнергию только в том случае, если есть «холодильник». Температура земли — +4, это 277 градусов кельвина.
Если вдруг удастся найти природный источник температуры, скажем −16 градусов, то есть 257 по кельвину, то КПД в лучше случае будет (277-257)/277 порядка 7% (см. цикл Карно). В реальности на таких температурах удастся добиться КПД в лучше случае 1-2%. И это нужен «бесконечный» источник вещества с температурой −16 градусов. По факту ничего такого не получается с пользой.
А вот перекачать тепло из одного места в другое, затратив энергию, термодинамика не запрещает. Поэтому мы тратим X работы и 4Х тепла перекачиваем из тёплой земли в дом. И да, все эти Х работы в итоге тоже выделятся в виде тепла. Поэтому получаются 500%.
Если сборка проекта через webpack, то можно просто добавить в конфиг это:
const CompressionPlugin = require('compression-webpack-plugin');
...
  new CompressionPlugin({
    filename: '[path].br[query]',
    algorithm: 'brotliCompress',
    test: /\.(html|css|ttf|eot|svg|js)$/,
    compressionOptions: { level: 11 },
    threshold: 1024,
    minRatio: 0.8,
  }),
  new CompressionPlugin({
    filename: '[path].gz[query]',
    test: /\.(html|css|ttf|eot|svg|js)$/,
    threshold: 1024,
    minRatio: 0.8,
  }),
...

(Ну и да, кастомно собранный nginx с поддержкой brotli тоже нужен)
Никого вечного двигателя, увы. Дополнительные 400% тепла берутся из «тёплой» земли. И работу из них не сошьёшь.
Это неправда. У тепловых насосов КПД не 100%, а до 500%.
Простыню append'ов можно сделать так:
attr_names = [
    'HOUSEID', 'HOUSEGUID', 'AOGUID', 'HOUSENUM', 'STRUCNUM', 
    'STRSTATUS', 'ESTSTATUS', 'STATSTATUS', 'IFNSFL', 'IFNSUL', 
    'TERRIFNSFL', 'TERRIFNSUL', 'OKATO', 'OKTMO', 'POSTALCODE', 
    'STARTDATE', 'ENDDATE', 'UPDATEDATE', 'COUNTER', 'NORMDOC', 
    'DIVTYPE', 'REGIONCODE'
]
for attr_name in attr_names:
    object.append(member.attrib.get(attr_name, None))            
david1978, как вы там? Черкните хотя бы один комментарий, мы волнуемся!
Я работал в немного похожей ситуации: банковская АБС из 1980-1990-х, куча inhouse-доработок сомнительного качества и язык RPGLE на AS400. Только ЗП, увы, была не за 99% квантиль… :(
Много лет кайфовал: изучил всё вдоль и поперёк. Прикрутил кучу фич, про которые вообще не думали, что на той системе так можно «задёшево». Ну, то есть схема была такая: остаётся свободное время, пилишь прототипчик какой-нибудь фичи. И пачка готовых экспериментов всё время лежит. Потом появляется задача, в которой одну из фич можно добавить. И ты уже точно знаешь, что прикрутишь её, скажем, за 2-3 дня. И это заказчика устраивает.
А я у себя настроил SSLH (см. habr.com/post/412779). И в итоге у меня открыты два порта: 80 (редиректит на 443) и 443. А уже через 443 идёт и телеграм, и openvpn, и ssh. И да, на «обычные» запросы отвечает nginx, раздаёт зеркало одного из моих проектов.
Казалось бы, это не так важно. Каждый день делаем реестр всех номеров. Через месяц выгружаем реестр в РСА. Они отвечают списком номеров, у которых на дату «месяц назад» не было ни одного оформленного полиса.
Ну, на ближайшие пару недель может и имеет смысл. Но с 1 ноября 2019 — уже всё. Там изоляция рунета. Уверен, как раз в таких ситуациях и будут применять.
С прошлого года есть филиал и в Москве: 21-school.ru (работают по лицензии школы 42).
Дополню, что там только офф-лайн, только на компьютерах школы, зато 24 × 7.
В московском офисе — это порядка 700 штук 27" iMac'ов.
С моей точки зрения (я был у них «в гостях» и разговаривал с отдельными студентами, они кое-что показывали) штука очень крутая. Особенно по сравнению многими ВУЗами. Хотя и не все аспекты кажутся мне правильными.
Раз уж про меня вспомнили, то вот сравнение нескольких реализаций. На списках несколько геморройнее, зато в 3 раза быстрее.

Код на python
from timeit import timeit


def eratosthenes1(N):
    simp, nonsimp = [2], set()
    for i in range(3, N + 1, 2):
        if i not in nonsimp:
            nonsimp |= {j for j in range(3 * i, N + 1, 2 * i)}
            simp.append(i)
    return simp


def eratosthenes2(N):
    simp, nonsimp = [2, 3], {i for i in range(3, N + 1, 3)}
    for i in range(5, int(N ** 0.5), 2):
        if i not in nonsimp:
            nonsimp |= {j for j in range(i * i, N + 1, 2 * i)}
            simp.append(i)
    simp.extend([j for j in range(i, N + 1, 2) if j not in nonsimp])
    return simp


def eratosthenes3(N):  # Возвращает список простых чисел от 2 до N
    if N < 2:
        return []
    A = [False, True] * ((N + 2) // 2)
    A[2] = True
    for i in range(3, int(N ** 0.5 + 1.5), 2):
        if A[i]:
            for j in range(i * i, N + 1, 2 * i):
                A[j] = False
    return [i for i in range(2, N + 1) if A[i]]

# Самая быстрая версия, N = 10**8, ~13c
def eratosthenes4(N):  # Возвращает список простых чисел от 2 до N
    if N < 2: return []
    A = [False, True] * ((N + 2) // 2)  # Про чётные всё очевидно
    simps = [2]
    sqrtN = int(N ** 0.5 + 1.5)  # Корень плюс ещё немного
    sqrtN += 1 - sqrtN % 2  # Делаем нечётным (это пригодится позже)
    for i in range(3, sqrtN, 2):
        if A[i]:
            simps.append(i)
            for j in range(i * i, N + 1, 2 * i):
                A[j] = False
    simps.extend(i for i in range(sqrtN, N + 1, 2) if A[i])  # Вот здесь важно, что sqrtN нечётный
    return simps


def eratosthenes5(n):  # Решето Грайса и Мисра (David Gries, Jayadev Misra), асимптотика O(n)
    lsd = [0] * (n + 1)
    simp = []
    for i in range(2, n + 1):
        if lsd[i] == 0:
            simp.append(i)
            lsd[i] = i
        for p in simp:
            if p * i > n:
                break
            lsd[p * i] = p
    return simp


funcs = [obj for name, obj in globals().items() if name.startswith('erat')]
N = 10 ** 8
setup = 'from __main__ import funcs, N'
for i in range(len(funcs)):
    print(timeit(stmt='funcs[{}](N)'.format(i), setup=setup, number=1))
# 59.081
# 41.303
# 14.553
# 12.582 <- eratosthenes4 в 3+ раза быстрее
# 75.451



А вот до кучи реализация на rust. У меня миллиард считает за 6с (ноутбучный core i5, 1.6GHz)
(third112)

Код eratosthenes4 на rust
use std::time::Instant;

fn eratosthenes4(n: usize) -> Vec<usize> {
    if n < 2 {
        return Vec::new();
    }
    let mut tst = vec![true; (n + 1) / 2];
    let mut simps = vec![2];
    let mut sqrt_n = ((n as f64).sqrt() + 1.5) as usize;
    sqrt_n += 1 - sqrt_n % 2;
    for i in (3..sqrt_n).step_by(2) {
        if tst[i>>1] {
            simps.push(i);
            for j in (i * i..(n + 1)).step_by(2 * i) {
                tst[j>>1] = false;
            }
        }
    }
    for i in (sqrt_n..(n + 1)).step_by(2).filter(|x| tst[x>>1]) {
        simps.push(i);
    }
    return simps;
}


fn main() {
    let now = Instant::now();
    let n = 1_000_000_000;
    let res = eratosthenes4(n);
    let dur = Instant::now().duration_since(now);
    println!("Duration: {:?}, len: {}", dur, res.len());
    // Duration: 6.0877631s, len: 50847534
}


(Не трогайте комментаторов моего сообщения, плз. Я сначала не заметил тег и написал комментарий. А потом понял и добавил PS. В результате комментарии от baldr и далее выглядят неуместно)

Информация

В рейтинге
Не участвует
Откуда
Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Бэкенд разработчик, Менеджер продукта
Ведущий
Python
Управление проектами
Алгоритмы и структуры данных
Asyncio