С такой фразой мне кинули ссылку на статью компании Mail.Ru Group от 2015 «Как выбрать язык программирования?». Если кратко, они сравнили производительность Go, Rust, Scala и Node.js. За первое место боролись Go и Rust, но Go победил.

Как написал автор статьи gobwas (здесь и далее орфография сохранена):
Эти тесты показывают, как ведут себя голые серверы, без «прочих нюансов» которые зависят от рук программистов.
К моему большому сожалению, тесты не были эквивалентными, ошибка всего лишь в 1 строчке кода поставила под сомнение объективность и вывод статьи.

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

Суть тестов

При тестировании выяснилось, что все претенденты работают примерно с одинаковой производительностью в такой постановке — все упиралось в производительность V8. Однако реализация задания не была лишней — разработка на каждом из языков позволила составить значительную часть субъективных оценок, которые так или иначе могли бы повлиять на окончательный выбор.
Итак, мы имеем два сценария. Первый — это просто приветствие по корневому URL:

GET / HTTP/1.1
Host: service.host

HTTP/1.1 200 OK

Hello World!

Второй — приветствие клиента по его имени, переданному в пути URL:

GET /greeting/user HTTP/1.1
Host: service.host

HTTP/1.1 200 OK

Hello, user

Первоначальный исходный код тестов


Node.js
var cluster = require('cluster');
var numCPUs = require('os').cpus().length;
var http = require("http");
var debug = require("debug")("lite");
var workers = [];
var server;

cluster.on('fork', function(worker) {
    workers.push(worker);

    worker.on('online', function() {
        debug("worker %d is online!", worker.process.pid);
    });

    worker.on('exit', function(code, signal) {
        debug("worker %d died", worker.process.pid);
    });

    worker.on('error', function(err) {
        debug("worker %d error: %s", worker.process.pid, err);
    });

    worker.on('disconnect', function() {
        workers.splice(workers.indexOf(worker), 1);
        debug("worker %d disconnected", worker.process.pid);
    });
});

if (cluster.isMaster) {
    debug("Starting pure node.js cluster");

    ['SIGINT', 'SIGTERM'].forEach(function(signal) {
        process.on(signal, function() {
            debug("master got signal %s", signal);
            process.exit(1);
        });
    });

    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
} else {
    server = http.createServer();

    server.on('listening', function() {
        debug("Listening %o", server._connectionKey);
    });

    var greetingRe = new RegExp("^\/greeting\/([a-z]+)$", "i");
    server.on('request', function(req, res) {
        var match;

        switch (req.url) {
            case "/": {
                res.statusCode = 200;
                res.statusMessage = 'OK';
                res.write("Hello World!");
                break;
            }

            default: {
                match = greetingRe.exec(req.url);
                res.statusCode = 200;
                res.statusMessage = 'OK';
                res.write("Hello, " + match[1]);    
            }
        }

        res.end();
    });

    server.listen(8080, "127.0.0.1");
}


Go
package main

import (
    "fmt"
    "net/http"
    "regexp"
)

func main() {
    reg := regexp.MustCompile("^/greeting/([a-z]+)$")
    http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        switch r.URL.Path {
        case "/":
            fmt.Fprint(w, "Hello World!")
        default:
            fmt.Fprintf(w, "Hello, %s", reg.FindStringSubmatch(r.URL.Path)[1])
        }
    }))
}


Rust
extern crate hyper;
extern crate regex;

use std::io::Write;
use regex::{Regex, Captures};

use hyper::Server;
use hyper::server::{Request, Response};
use hyper::net::Fresh;
use hyper::uri::RequestUri::{AbsolutePath};

fn handler(req: Request, res: Response<Fresh>) {
    let greeting_re = Regex::new(r"^/greeting/([a-z]+)$").unwrap();

    match req.uri {
        AbsolutePath(ref path) => match (&req.method, &path[..]) {
            (&hyper::Get, "/") => {
                hello(&req, res);
            },
            _ => {
                greet(&req, res, greeting_re.captures(path).unwrap());
            }
        },
        _ => {
            not_found(&req, res);
        }
    };
}

fn hello(_: &Request, res: Response<Fresh>) {
    let mut r = res.start().unwrap();
    r.write_all(b"Hello World!").unwrap();
    r.end().unwrap();
}

fn greet(_: &Request, res: Response<Fresh>, cap: Captures) {
    let mut r = res.start().unwrap();
    r.write_all(format!("Hello, {}", cap.at(1).unwrap()).as_bytes()).unwrap();
    r.end().unwrap();
}

fn not_found(_: &Request, mut res: Response<Fresh>) {
    *res.status_mut() = hyper::NotFound;
    let mut r = res.start().unwrap();
    r.write_all(b"Not Found\n").unwrap();
}

fn main() {
    let _ = Server::http("127.0.0.1:8080").unwrap().handle(handler);
}


Scala
package lite

import akka.actor.{ActorSystem, Props}
import akka.io.IO
import spray.can.Http
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import akka.actor.Actor
import spray.routing._
import spray.http._
import MediaTypes._
import org.json4s.JsonAST._

object Boot extends App {
  implicit val system = ActorSystem("on-spray-can")
  val service = system.actorOf(Props[LiteActor], "demo-service")
  implicit val timeout = Timeout(5.seconds)
  IO(Http) ? Http.Bind(service, interface = "localhost", port = 8080)
}

class LiteActor extends Actor with LiteService {
  def actorRefFactory = context
  def receive = runRoute(route)
}

trait LiteService extends HttpService {
  val route =
    path("greeting" / Segment) { user =>
      get {
        respondWithMediaType(`text/html`) {
          complete("Hello, " + user)
        }
      }
    } ~
    path("") {
      get {
        respondWithMediaType(`text/html`) {
          complete("Hello World!")
        }
      }
    }
}


Подлый удар в спину


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

Don't click
Дело в том, что в примере Node.js и Go компиляция регулярного выражения происходит единожды, тогда как в Rust компиляция выполняется на каждый запрос. Про Scala ничего сказать не могу.

Выдержка из документации к regex для Rust:

Example: Avoid compiling the same regex in a loop



It is an anti-pattern to compile the same regular expression in a loop since compilation is typically expensive. (It takes anywhere from a few microseconds to a few milliseconds depending on the size of the regex.) Not only is compilation itself expensive, but this also prevents optimizations that reuse allocations internally to the matching engines.

In Rust, it can sometimes be a pain to pass regular expressions around if they're used from inside a helper function. Instead, we recommend using the lazy_static crate to ensure that regular expressions are compiled exactly once.

For example:

#[macro_use] extern crate lazy_static;
extern crate regex;

use regex::Regex;

fn some_helper_function(text: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new("...").unwrap();
    }
    RE.is_match(text)
}

fn main() {}

Specifically, in this example, the regex will be compiled when it is used for the first time. On subsequent uses, it will reuse the previous compilation.

Выдержка из документации к regex для Go:

But you should avoid the repeated compilation of a regular expression in a loop for performance reasons.

Как допустили такую ошибку? Я не знаю… Для такого прямолинейного теста это является существенной просадкой в производительности, ведь даже в комментариях автор указал на тормознутость регулярок:
Спасибо! Я тоже думал было переписать на split во всех примерах, но потом показалось, что с regexp будет более жизненно. При оказии попробую прогнать wrk со split.

Упс.

Восстанавливаем справедливость


Исправленный тест Rust
extern crate hyper;
extern crate regex;

#[macro_use] extern crate lazy_static;

use std::io::Write;
use regex::{Regex, Captures};

use hyper::Server;
use hyper::server::{Request, Response};
use hyper::net::Fresh;
use hyper::uri::RequestUri::{AbsolutePath};

fn handler(req: Request, res: Response<Fresh>) {
    lazy_static! {
        static ref GREETING_RE: Regex = Regex::new(r"^/greeting/([a-z]+)$").unwrap();
    }

    match req.uri {
        AbsolutePath(ref path) => match (&req.method, &path[..]) {
            (&hyper::Get, "/") => {
                hello(&req, res);
            },
            _ => {
                greet(&req, res, GREETING_RE.captures(path).unwrap());
            }
        },
        _ => {
            not_found(&req, res);
        }
    };
}

fn hello(_: &Request, res: Response<Fresh>) {
    let mut r = res.start().unwrap();
    r.write_all(b"Hello World!").unwrap();
    r.end().unwrap();
}

fn greet(_: &Request, res: Response<Fresh>, cap: Captures) {
    let mut r = res.start().unwrap();
    r.write_all(format!("Hello, {}", cap.at(1).unwrap()).as_bytes()).unwrap();
    r.end().unwrap();
}

fn not_found(_: &Request, mut res: Response<Fresh>) {
    *res.status_mut() = hyper::NotFound;
    let mut r = res.start().unwrap();
    r.write_all(b"Not Found\n").unwrap();
}

fn main() {
    let _ = Server::http("127.0.0.1:3000").unwrap().handle(handler);
}


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

Окружение


Все тесты запускались на локалхосте, без всяких виртуалок, ибо лень. Будет замечательно, если автор предоставит бенчмарки со своего железа, я вставлю апдейтом, вот специально для него репозиторий с тестами, где, кстати, зафиксированы растовые библиотеки на момент написания оригинальной статьи 2015.12.17 (я надеюсь, что все).

  1. Ноут
    • Intel® Core(TM) i7-6820HQ CPU @ 2.70GHz, 4+4
    • CPU Cache L1: 128 KB, L2: 1 MB, L3: 8 MB
    • 8+8 GB 2133MHz DDR3

  2. Десктоп
    • Intel® Core(TM) i3 CPU 560 @ 3.33GHz, 2+2
    • CPU Cache L1: 64 KB, L2: 4 MB
    • 4+4 GB 1333MHz DDR3

  3. go 1.6.2, released 2016/04/20
  4. rust 1.5.0, released 2015/12/10. Да, я специально взял старую версию Rust.
  5. Простите, любители Scala и Node.js, этот холивар не про вас.

Интрига


ab

Попробуем выполнить 50 000 запросов за 10 секунд, с 256 возможными параллельными запросами.

Десктоп


ab -n50000 -c256 -t10 "http://127.0.0.1:3000/
Label Time per request, ms Request, #/sec
Rust 11.729 21825.65
Go 13.992 18296.71

ab -n50000 -c256 -t10 "http://127.0.0.1:3000/greeting/hello"
Label Time per request, ms Request, #/sec
Rust 11.982 21365.36
Go 14.589 17547.04

Ноут


ab -n50000 -c256 -t10 "http://127.0.0.1:3000/"
Label Time per request, ms Request, #/sec
Rust 8.987 28485.53
Go 9.839 26020.16

ab -n50000 -c256 -t10 "http://127.0.0.1:3000/greeting/hello"
Label Time per request, ms Request, #/sec
Rust 9.148 27984.13
Go 9.689 26420.82

— Подожди, — скажет читатель. — И стоило тебе строчить статью ради каких-то 500rps?! Ведь это доказывает, что не важно на чем писать, все языки одинаковые!

И тут вступает в дело мой шнур. Шнур для зарядки ноутбука, разумеется.

Ноут на подзарядке


ab -n50000 -c256 -t10 "http://127.0.0.1:3000/"
Label Time per request, ms Request, #/sec
Rust 5.601 45708.98
Go 6.770 37815.62

ab -n50000 -c256 -t10 "http://127.0.0.1:3000/greeting/hello"
Label Time per request, ms Request, #/sec
Rust 5.736 44627.28
Go 6.451 39682.85

Стой, Go, ты куда?



Выводы


Я допускаю, что статья компании Mail.Ru Group содержала непреднамеренную ошибку. Тем не менее, за 1.5 года ее прочитали 45 тысяч раз, и её выводы могли сформировать предвзятое отношение в пользу Go при выборе инструментов, ведь Mail.Ru Group, несомненно, прогрессивная и технологичная компания, к чьим словам стоит прислушаться.

И всё это время Rust совершенствовался, посмотрите на «The Computer Language Benchmarks Game» Rust vs Go за 2015 и 2017 года. Отрыв в производительности только растет.

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

А если тебе нравится Rust, вливайся в сообщество, нам многого не хватает. Не хотите работать бесплатно? Присоединяйтесь к проекту Tox и пишите на Rust за деньги (пишите мне в личку).

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

Let the Holy War begin!

Комментарии (255)


  1. MikeLP
    19.09.2017 23:41
    +25

    Простите, любители Scala и Node.js, этот холивар не про вас.

    «За ноду и двор стреляю в упор.»
    шютка
    (не смешная)


    1. apelsyn
      20.09.2017 16:38

      Ноду через модуль cluster балансировать не оптимально, для этого есть специально написанные инструменты nginx или haProxy. Поэтому по ноде тесты сомнительные.


      Попробуйте так, ставим ноду 8.5
      создаем index.js


      var http = require("http");
      var server;
      
      server = http.createServer();
      
      server.on('listening', function() {
          console.log(`Listening ${server._connectionKey}`);
      });
      
      var greetingRe = new RegExp("^\/greeting\/([a-z]+)$", "i");
      server.on('request', function(req, res) {
          var match;
      
          switch (req.url) {
              case "/": {
                  res.statusCode = 200;
                  res.statusMessage = 'OK';
                  res.write("Hello World!");
                  break;
              }
      
              default: {
                  match = greetingRe.exec(req.url);
                  res.statusCode = 200;
                  res.statusMessage = 'OK';
                  res.write("Hello, " + match[1]);
              }
          }
      
          res.end();
      });
      
      server.listen(8080, "127.0.0.1");

      Убираем балансировку и получаем тот же результат


  1. SealTV
    20.09.2017 00:33
    +2

    Сколько ещё будут сравнивать Go и Rust, очевидно, же, что Rust будет быстрее, но в тоже время разница в читаемости кода тоже существенна и тут Go выигрывает на мой взгляд.


    1. humbug Автор
      20.09.2017 00:34
      +18

      Мне очевидно, вам очевидно, а в бенчмарках Mail.Ru Group почему-то победил Go. Смотрите на таблицу в оригинальной статье под заголовком "Обобщение".


    1. c0va23
      20.09.2017 11:29
      +6

      Читаемость у Go, конечно лучше. Как минимум из-за более простого и чистого синтаксиса. Но количество кода на Go, в большинстве случаев будет гораздо больше. В некоторых случая разница в количестве кода будет в разы. А как мы все знаем, чем меньше кода — тем меньше шанс допустить ошибку.

      P.S. Сам использую Go, где нужно быстро получить результат. А где важна надёжность использую Rust.


    1. khim
      20.09.2017 16:36
      +7

      Знаете, если бы читаемость была бы основным критерием, то мы сейчас писали бы на Паскале, Аде или ещё каком-нибудь потомке Алгола.

      Одако нет же: весь спор идёт о том выбрали ли JavaScript, Go, Rust или PHP! А ведь все эти языки в смысле синтаксиса — С-подобные, что, как бы, явно тяжелее читается. Без подготовки, во всяком случае.


    1. akzhan
      20.09.2017 21:58
      +3

      Что? по мне так Go самый нечитаемый и клавиатурно набивательно ориентированный язык.


      1. SealTV
        20.09.2017 22:43
        +1

        Ну для меня Go более читабельный, чем Rust. Но это всё весьма субъективно и я думаю ни когда не будет согласия между всеми в этом вопросе)


    1. kalininmr
      21.09.2017 18:12

      несколько спорно.
      со структурами нужно додумывать чтотам куда и как скопировалось при наследовании и все такое.


  1. mersinvald
    20.09.2017 01:14
    +2

    А не смущает, что hyper взяли старой версии, еще не асинхронный?


    1. humbug Автор
      20.09.2017 01:29
      +19

      Я взял hyper не старой версии, а ту, что была доступна автору оригинальной статьи в декабре 2015 года. Более того, я сидел на crates.io пару часов и фиксил ручками Cargo.lock, чтобы принудительно дауншифтнуть версии библиотек до того года. Иначе это была бы некорректная статья с заголовком: "Давайте сравним go 2016 года и новые модные библиотеки Rust".


      1. mersinvald
        20.09.2017 02:41
        -1

        deleted


  1. Siemargl
    20.09.2017 01:16
    +3

    За эти годы Раст сменил уже десяток версий.

    Сравнивать еще было бы неплохо память/кол-во запросов. Потому что конкуренция тут будет серьезней


    1. humbug Автор
      20.09.2017 01:33
      +10

      За эти годы Раст сменил уже десяток версий.

      Правильно, но я специально сделал путешествие в прошлое, чтобы Go и Rust были в равных условиях.


      1. MacIn
        20.09.2017 16:16
        +2

        А зачем? Ну, доказали вы, что старая статья — врет. Кому это интересно? Как дела обстоят сегодня?


    1. VovanZ
      20.09.2017 12:11

      память
      У Go есть рантайм и сборка мусора. Думаю, что тут отрыв будет ещё сильнее.


  1. Nagg
    20.09.2017 01:16
    +34

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


    Java: (выгружаем всю таблицу в память из sql а потом находим нужную строку)


    List<User> allUsers = userRepository.findAll();
    return allUsers.get(random.nextInt(allUsers.size()));

    Go: (находим строку по sql запросу)


    rows, err := db.Queryx("select * from users order by random() limit 1")

    Нет, это не шутка — это публиковалось тут на хабре и много людей так же просмотрело и возможно сделали по этому бреду вывод о "тормозной джаве".


    1. justboris
      20.09.2017 14:11

      Нет, это не шутка — это публиковалось тут на хабре

      а ссылку привести можно? Без нее выглядит как необоснованный наброс.


      1. zirix
        20.09.2017 16:19
        +1

        sohabr.net/habr/post/317006/?version=207685

        Было несколько статей с подобным (или этим же) кодом


        1. justboris
          20.09.2017 17:07
          -1

          так это же не Habrahabr.


          1. mayorovp
            20.09.2017 17:13
            +5

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


            1. Nagg
              21.09.2017 15:56
              -2

              Никто ничего не прятал :-) https://habrahabr.ru/post/316944/ 11.1к просмотров.
              UPD: а нет, прошу прощения, это другая (ссылалась на ту)


              1. mayorovp
                21.09.2017 15:58

                Это совсем другой пост. Что вы нашли между ними общего?


          1. marsermd
            20.09.2017 17:15

            Это действительно не хабр, но автор собирался опубликовать эту статью на хабре. И опубликовал её. Но скрыл, возможно из-за негативной реакции сообщества.


      1. momont
        20.09.2017 22:15

        В черновиках:
        7 декабря 2016 в 4:49 | сохранено в 14:29
        Скорость работы Vapor по сравнению с другими веб-фреймворками
        sohabr.net/habr/post/317006


      1. PaveLiArcH
        20.09.2017 22:15

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


        1. justboris
          21.09.2017 00:00
          -1

          Ну ок, показали автору на ошибку, он удалил статью, инцидент исчерпан.


          Зачем пинать лежачего и вспоминать об этом здесь?


          1. Nagg
            21.09.2017 15:56

            Никто статью не удалял, вот она, висит https://habrahabr.ru/post/316944/ 11.1к просмотров.
            UPD: а нет, прошу прощения, это другая (ссылалась на ту)


  1. robert_ayrapetyan
    20.09.2017 02:38
    +2

    Хз, в highloadcup только два раста в топ-50 (причем лучший — на 31 месте), при этом 10 решений на Го (лучший «чистый» Го на 15-ом).


    1. codesign
      20.09.2017 03:03
      +19

      Это говорит скорее о том, что в Rust мало людей
      Так-то я и Perl вывел в top 50 ;)


      1. robert_ayrapetyan
        20.09.2017 03:39
        +1

        В перле крутой http-сервер кстати (из коробки), одно из откровений чемпионата


      1. phponelove
        20.09.2017 15:33
        -1

        Это говорит скорее о том, что в Rust мало людей

        Почему же? Действительно, количество людей имеющих возможность вывести некий язык «в топ» зависит от общество кол-ва людей в этом языке. Но.

        У людей в расте есть дополнительная мотивация участия, меньшая конкуренция, ну и язык декларируется как лоулевел и альтернатива С/С++ — т.е. он про системщину. Декларация подобного требует от комьюнити опыта в данной сфере, а иначе как можно агитировать?

        И вопрос остаётся открытым — где все эти люди? Остаётся только верить в то, что все они были заняты в это время.


        1. TargetSan
          20.09.2017 17:24
          +2

          По отзывам довольно много приходит питонистов и рубистов, которым надо оптимизировать какой-то нагруженный кусок, а писать на С/С++ боязно. Плюс — хайлоад кап был чисто русский, так что могло быть просто мало народу в русскоязычном комьюнити. Я например узнал о соревновании сильно постфактум.


          1. phponelove
            20.09.2017 17:44

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

            Очень много. По крайней мере агитаторов.

            Я например узнал о соревновании сильно постфактум.

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


      1. morozovsk
        20.09.2017 17:01
        +1

        К сожалению мало людей знает про заслуги Perl на highloadcup, потому что ваша статья опубликована только на гитхабе, хотя статья хорошая и читается на одном дыхании и стоило бы поделиться ею с остальными пользователями хабра. Но выбор ваш. Я хотел написать обзорную статью по всем языкам программирования в highloadcup, но к сожалению некоторые участники указывают ненастоящие данные и боюсь ценность выводов на основе заведомо ложной информации будет стремиться к нулю. Вначале я недооценивал перл и даже думал, что кто-то в шутку указал этот стек, пока не прочитал вашу статью. Может кто-то до сих пор так считает.


        1. unsafePtr
          20.09.2017 21:31

          Я полез в репо автора, но к сожалению никакой статьи там не нашел. Никогда не видел в глаза Perl, просто интересно о чём статья.



    1. Halt
      20.09.2017 08:06
      +3

      mkpankov на реддите написал ретроспективный анализ своей реализации, где разобрал причины.


      1. ProRunner
        20.09.2017 15:47
        +3

        Долго думал, что такое bicycle-building, пока не перевел на русский. Пример того, как не нужно буквально переводить идиомы.


        1. MacIn
          20.09.2017 16:18
          +2

          reinventing the wheel было бы уместно.


        1. red75prim
          20.09.2017 20:44
          +1

          Зато bicyclomatic complexity попала в цитату недели.


    1. TargetSan
      20.09.2017 09:58
      +2

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


      1. phponelove
        20.09.2017 14:14

        Что мешало всем остальным языкам «оптимизировать» «свои» «алгоритмы»? Я уж не буду говорить о том, что именно язык прямо и косвенно влияет на возможность оптимизаций. Косвенно через компетенцию автора в данном контексте, а прямо через возможности языка.

        Приведу простые примеры. Откуда у человека, который писал на готовом веб-стеке на том же пхп/ноде есть необходимые навыки сетевого программирования? Как вы будите оптимизировать аллокации на языке с ГЦ? А с неуправляемым ГЦ?

        И таких примеров массы.


        1. RPG18
          20.09.2017 14:24
          +2

          Как вы будите оптимизировать аллокации на языке с ГЦ?

          Точно также, как буду оптимизировать аллокации на языке без ГЦ. Например на C++ стандартная практика использования пулов объектов/памяти.


          1. phponelove
            20.09.2017 14:46
            +1

            Например на C++ стандартная практика использования пулов объектов/памяти.

            Это уже не оптимизация, а подступы через известное место. Дело в том, что в языках с ГЦ нету памяти. Как там обстоят дела с placement new и иже с ним. Такими темпами мы потонем в тоннах бойлерплейта. Одно дело иметь уже заточенные средства, а другое дело иметь язык с абсолютно обратной логикой.

            Просто пример. В крестах мы взяли 100n памяти и проинициализировали её внутри логики. Память мы взяли за ноль. Как это сделать в языке с ГЦ? А никак. Мы либо будем долбить пуши в массив, либо инициализировать его два раза.

            При этом не всё так просто и те же стоки в пулы не засунешь. Как мы будем реализовать строки? Через массивы? Как мы будем их инициализировать? Где мы возьмём мемкопи? Где мы возьмём конкурентоспособную реализацию сишным строкам? Реализуем? Сомневаюсь.

            Это я не говорю о том, что пролетаем со всем тем рантаймом, что предоставляет нам язык. Он весь повязан на гц. И опять же — в данном случае мы опять упираемся во вторую причину.


            1. RPG18
              20.09.2017 15:42
              -1

              Дело в том, что в языках с ГЦ нету памяти. Как там обстоят дела с placement new и иже с ним.

              Пул объектов?


              сишным строкам?

              Сишниые строки в самом C/C++ редко использую, т.к. strlen пробегает по всей строке и это медленно.


              Мы либо будем долбить пуши в массив, либо инициализировать его два раза.

              А в C++ не так? В критичных местах в C++ да же предварительно не очищается память, просто помечаем как "свободную".


              1. phponelove
                20.09.2017 16:22
                +1

                Пул объектов?

                Дело в том, что память и объекты — это разные вещи. Объекты могут и обычно несут в себе какую-то логику инициализации. Память же — это просто память.

                Сишниые строки в самом C/C++ редко использую, т.к. strlen пробегает по всей строке и это медленно.

                Сишные строки как раз-таки и используются. Длинны в С++-строке это просто некая оптимизация получения длинные и не более того.

                Есть всякие поиски подстрок, поиски символов и прочее. А медленно — это только в кейсе получения длинны. Остальные операции со строками требует прохода по ней и проверка символа на ноль — операция с нулей(в большинстве случаев) стоимостью. Какая разница что делать — сравнивать два указателя, либо сравнивать текущий символ с нулём?

                А в C++ не так?

                Да, в С++ это не так. Можно выделить кусок памяти не создавая объектов, а потом создать их в уже выделенной памяти во время её обхода.

                В критичных местах в C++ да же предварительно не очищается память, просто помечаем как «свободную».

                Что понимается под «очищением памяти»? Возврат страниц в систему? Подобное поведение свойственно любым менеджерам памяти. В реализации почти всех языков берут какой-нибудь jmalloc/tcmalloc/gnumallo, либо свой велосипед. Поэтому менеджер памяти в других языках не обладает какими-то резко другими свойствами.


                1. RPG18
                  20.09.2017 16:46

                  Объекты могут и обычно несут в себе какую-то логику инициализации.

                  Дело было в placement new, который в C++ вызывает конструирование объекта. А конструирование объекта, это инициализация.


                  Длинны в С++-строке это просто некая оптимизация получения длинные и не более того.

                  Только в C++ строки это контейнер, у которого есть lenght и capacity. И если хочу "очистить строку", то сбрасываю длину. И алгоритмы оперирующие на длину, а не на нуль символ, как работали так и работают. Поэтому да же в программах на Си, можно увидеть свою реализацию строк.


                  Можно выделить кусок памяти не создавая объектов, а потом создать их в уже выделенной памяти во время её обхода.

                  И кроме как embedded это особо никому не нужно, т.к. можно исользовать пул объектов.


                  Что понимается под «очищением памяти»?
                  Какой-нибудь memset с 0.


                  1. mayorovp
                    20.09.2017 17:01
                    +2

                    Дело было в placement new, который в C++ вызывает конструирование объекта. А конструирование объекта, это инициализация.

                    Вот именно! В С++ есть возможность взять область памяти из пула и инициализировать ее как объект путем вызова конструктора через placement new.


                    В C# или Java (пример языков с GC) такой возможности нет — а значит, нужно выносить логику инициализации из конструктора в метод инициализации. При этом теряются многие языковые фишки — к примеру, поля только для чтения (readonly/final) — а ведь на их неизменяемости могут быть завязаны оптимизации на уровне JIT. Получается, оптимизация аллокаций может не ускорить программу, а замедлить.


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


                    1. RPG18
                      20.09.2017 17:13
                      -1

                      Лично в Go таких проблем нет, потому что в нем есть Go sync.Pool , который вовсю используется в fasthttp. Который показал неплохой результат в прошедшем highloadcup.


                      1. mayorovp
                        20.09.2017 17:23
                        +1

                        В приведенном вами посте рассматривается пул простых объектов — массивов байт. Буферы в виде массивов байт неплохо размещаются в пуле в любом языке программирования, не только в Go.

                        Но изначально-то шла речь о пулах произвольных объектов.


                        1. RPG18
                          20.09.2017 17:25
                          -1

                          sync.Pool универсальный способ. Ему все равно, что хранить.


                          1. mayorovp
                            20.09.2017 17:31
                            +1

                            Да, но разработчику не все равно какие объекты помещать в пул.


                  1. MikailBag
                    20.09.2017 17:04

                    А зачем занулять память(кроме конечно всяких сверхсекретных данных типа ключа шифрования)?


                    1. MacIn
                      20.09.2017 17:10

                      Чтобы данные были преинициализированы. Те же логические переменные. Ссылки/указатели тоже.


                    1. RPG18
                      20.09.2017 17:16
                      +1

                      Что бы легче найти косяки с работой памяти. Если у тебя в памяти мусор, то программа на C++ еще может делать вид, что работает. А если попробует записать что-то в nullptr, то это сразу будет видно.


                      1. phponelove
                        20.09.2017 18:14
                        -1

                        Что бы легче найти косяки с работой памяти.

                        Это ложная уверенность, а любая ложная уверенность способствует большему кол-во ошибок, нежели что-то иное.

                        А если попробует записать что-то в nullptr, то это сразу будет видно.

                        В этом вся суть — мы взяли какой-то кейс и выдали его за все косяки, либо за какую-то весомую их часть. Это не так.

                        Разименование адреса «на прямую» достаточно редкий кейс, особенно в современном С++. new через new — уже не модно — это не жава.

                        Нулевой this вызывать функции позволяет, любые поля, кроме нулевого — будут не nullptr(скорее всего оно попадёт в нулевую страницу, но это просто особенность модели памяти и вас тут просто повезло, ведь вы говорили о nullptr). Все филды после 4к — уже мимо. Массивы — мимо.

                        Плюс, есть много кейсов, где это только навредит. Получили в оффсет ноль — не получили сегфолт, а получили мусор — получили сегфолт.
                        struct{arr[10];}.arr[offset] = 123;


                        На самом деле в любой программе используется малая часть адресспейса. Сколько там там памяти на топовой ноде? Одна миллиардная доля? Даже если это мы заммапим сотни петабайт — это копейки. Это даже не один процент.

                        Исходя из всего этого шанс разименовывая мусор попасть не на сегфолт достаточно туманны.


                  1. phponelove
                    20.09.2017 17:38

                    Дело было в placement new, который в C++ вызывает конструирование объекта. А конструирование объекта, это инициализация.

                    Дело было не в этом. Зачем обманывать?

                    Был определён кейс «выделить память и инициализировать», допустим — инициализировать очередь для обработки. На самом деле даже это неважно — просто инициализировать память.

                    В языка с ГЦ память будет проинициализирована ДВА раза. В С++ один раз. Плюс, ещё остаётся открытый вопрос о том, можно ли вообще аллоцировать массив за одну аллокацию.

                    Только в C++ строки это контейнер

                    Строк в С++ нет, как и в си. Есть std::string, но строки на нём не заканчиваются. Даже если поверить в то, что строки есть, так же в С++ есть сроки из си. С какой стороны не взгляни — утверждение неверное.
                    у которого есть lenght и capacity. И если хочу «очистить строку», то сбрасываю длину.

                    И что же из этого следует? Какое отношение это имеет к моей цитате? Это её опровергает, либо что?

                    *str = 0; Имеет ту же семантику. Дальше что? std::string, кстати, делает то же самое — сишное *str = 0, только к этому изменяет ещё size.

                    И алгоритмы оперирующие на длину, а не на нуль символ, как работали так и работают.

                    Начнём с того, что ничего не запрещает std::string изменять «нуль-символ». Т.к. в крестах нет реаллока, а у c_str() сложность константная, то срока обязана иметь капасити +1 для нуля. Уже давно даже data() нуль-терминированная.

                    Таким образом через что не возьми данные из std::string — сишные функции работать будут. Тут вы соврали.

                    Если вы хотели привести контр-пример, то надо было приводить нуль-символы в строке. Но опять же есть memchr(), memcpy().

                    Поэтому да же в программах на Си, можно увидеть свою реализацию строк.

                    Поэтому — это почему? Из-за lenght у std::string в С++? Сомневаюсь. Поэтому явно от С++ не зависит.

                    А оптимизацию для lenght можно прикрутить к чему угодно. И из этого мало что следует.

                    Велосипеды-обёртки поверх сишных строк строками не являются.

                    И кроме как embedded это особо никому не нужно, т.к. можно исользовать пул объектов.

                    Не можно. Это раз, а два — к чему ваши оценки? Вы говорили о чём? О том, что можно делать то же самое, а теперь вы пытаетесь избавиться от неудобных примеров оптимизаций.

                    Ну и голословные утверждения про «не нужно» вы так же чем-то сможете подтвердить?

                    Какой-нибудь memset с 0.

                    Это не очищение памяти. И с по каким таким причинам она вдруг должна «очищаться»?


                    1. 0xd34df00d
                      20.09.2017 19:05
                      +1

                      Таким образом через что не возьми данные из std::string — сишные функции работать будут. Тут вы соврали.

                      В std::string вполне может быть нулевой символ до символа на позиции size, std::string продолжит работать, а сишные функции — нет.


                      1. phponelove
                        20.09.2017 19:16
                        -1

                        Если вы хотели привести контр-пример, то надо было приводить нуль-символы в строке. Но опять же есть memchr(), memcpy().

                        Это что такое?


                        1. phponelove
                          20.09.2017 20:27

                          Я, неверное, непонятно и глупо ответил. Чтобы подобно не повторялось — дополню.

                          Дело в том, что отвечающий в ответе на мой комментарий описал ту ситуацию, которая уже была описана мною в том комментарии, на который он, собственно, и ответил.


                        1. 0xd34df00d
                          20.09.2017 20:57

                          А memcat какой-нибудь тоже есть, или memlen?


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


                          1. phponelove
                            21.09.2017 00:13

                            А memcat какой-нибудь тоже есть, или memlen?


                            Изначально было про то, что сишные функции для работы со строками в рамках std::string не применимы по причине отсутствия нуля после ресайза. Я доказал, что это не так.

                            Далее я помог автору комментария и привёл реальный пример( валидный для std::string), но невалидный для сишных строк. Вы зачем-то пришли и повторили мне то, что я итак сказал до вас. Зачем?

                            А теперь играете в игру «игнорирую всё» — зачем?

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

                            Зачем мне нулевые символы? Ну хорошо — придётся таскать, и?

                            Это отменяет что-то ранее сказанное мною, либо противоречит чему-то? Это ответ на моё утверждение намного выше?

                            Длинны в С++-строке это просто некая оптимизация получения длинные и не более того.

                            Это? Ну дак надо отвечать на тот комментарий, а не на другой.

                            Да и как я уже сказал — нулевые символы это больше надуманный кейс, чем реальный. От того я его и не рассматриваю. Если хотите — пусть будет length ещё и для хранения нулевых символов. Сломается ::data(), ::c_str(), но что поделать.


                            1. 0xd34df00d
                              21.09.2017 00:18

                              Прошу прощенья, если не уловил контекст целиком.


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


                              data/c_str не сломается, кстати. std::string other { str.data(), str.size() } вполне корректно отработает, просто надо быть осторожным.


                              1. phponelove
                                21.09.2017 01:18

                                data/c_str не сломается

                                Сломается — это будет совсем не строка, что ожидается.


                                1. 0xd34df00d
                                  21.09.2017 02:13

                                  Кем ожидается? Разве в стандарте написано, что там не будет нулей?


                                  1. phponelove
                                    21.09.2017 02:26
                                    +1

                                    От ::data()/::c_str() ожидается нуль-терминированная строка аналогичная строке(std::string, у которой методы вызваны), а не её подстрока.


                                    1. 0xd34df00d
                                      22.09.2017 04:54
                                      +2

                                      Так она вся и возвращается. А что там нули посередине — ну извините.


        1. TargetSan
          20.09.2017 14:49
          +1

          Что мешало всем остальным языкам «оптимизировать» «свои» «алгоритмы»? Я уж не буду говорить о том, что именно язык прямо и косвенно влияет на возможность оптимизаций. Косвенно через компетенцию автора в данном контексте, а прямо через возможности языка.
          Приведу простые примеры. Откуда у человека, который писал на готовом веб-стеке на том же пхп/ноде есть необходимые навыки сетевого программирования?

          Здесь не совсем понял, кого вы защищаете, а кому пеняете.


          • Си — КМК всё ясно, это язык, тождественный языку интерфейса системных библиотек. К тому же, до недавнего времени ему по факту не было альтернативы для таких задач.
          • Го — следуя вашей логике, откуда у человека, который писал на готовом net/http, необходимые навыки сетевого программирования?
          • Rust — упомянутые вами средства оптимизации там есть, но их надо применить; было ли это сделано в топовом решении — я не знаю.
          • А вообще в топ-50 попало решение на Perl — что тоже кое о чём говорит.

          Или уточните, о чём речь.


          Как вы будите оптимизировать аллокации на языке с ГЦ?

          Эээ… пулинг и буферы, как и без ГЦ? Если конечно стек на этом языке такое позволяет.


          А с неуправляемым ГЦ?

          Это как? ГЦ который сам в истерике выделяет и удаляет память? :)


          1. phponelove
            20.09.2017 16:05

            Здесь не совсем понял, кого вы защищаете, а кому пеняете.

            Я никого конкретного не защищаю. Защищаю одно — объективность.

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

            Почему же? Какой-нибудь с89 не далеко ушел от паскаля, да и сотни других языков из той же весовой категории. Правда, они ничего весомого предложить не могли, но что поделать. Это свойство «эпохи».

            В те времена у си даже основной киллерфичи не было — сильного компилятора. И выиграть его было проще. Т.е. ситуация была аналогична той, что есть сейчас. Только сейчас ллвм на халяву даёт такой компилятор кому угодно. Сколько языков повылазило( в частности раст).

            Го — следуя вашей логике, откуда у человека, который писал на готовом net/http, необходимые навыки сетевого программирования?

            Да, с го в данной ситуации история та же, что и с пхп/нодой. Я просто привёл более понятные примеры.

            Rust — упомянутые вами средства оптимизации там есть, но их надо применить; было ли это сделано в топовом решении — я не знаю.

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

            Поэтому это и даёт возможность людям умеющим оптимизировать код — делать это на любом языке, но — есть нюансы. И я их так же определил. Что бы вы не делали, но если язык не позволяет опуститься на тот уровень, дать ту свободу, что нужна для оптимизации — вы это не реализуете.

            А вообще в топ-50 попало решение на Perl — что тоже кое о чём говорит.


            github.com/Mons/hlcup/blob/master/libs/Local-HTTPServer/picohttpparser.c — это что? А сколько сишного рантайма в перле?

            Понимаете в чём штука, когда мы делаем подобным бенчмарки — их смысл в чём? Смысл в том, чтобы выявить инструменты и людей, которые способны реализовывать кастомные решения.

            Можно взять готовый сишный код парсера хттп, прикрутить его к питону. А если завтра нам нужно будет не хттп? Мы так же будем искать сишное решение? А если его нет? Будем писать на си?

            То же самое и со всем остальным. Надо отличать дефолтные кейсы от возможностей языка в общем. Ведь когда эти дефолтные кейсы кончаются — начинается ахтунг.

            Эээ… пулинг и буферы, как и без ГЦ? Если конечно стек на этом языке такое позволяет.

            Я выше отвечал по этому поводу.

            Это как? ГЦ который сам в истерике выделяет и удаляет память? :)

            Я не эксперт в ГЦ, но я видел некие хинты для гц в языках. Возможно где-то пошли ещё дальше.


            1. TargetSan
              20.09.2017 17:37

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


              Вы начали с того, что топовое решение на Rust попало только на 31-е место, а вот на Go — аж на 15-е (потом поправили что на 11-е).


              Я возразил, что на таком уровне вопрос уже не в языке, а в конкретных оптимизациях.


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


              Просто уточню, что решение на Rust (раз уж за него зацепились) отставало от 1-го места по очкам менее чем вдвое. И именно в этом контексте я и написал, что в таких условиях решает не язык, а конкретные оптимизации.


              1. phponelove
                20.09.2017 17:50

                Вы начали с того, что топовое решение на Rust попало только на 31-е место, а вот на Go — аж на 15-е (потом поправили что на 11-е).

                Это был не я.

                Просто уточню, что решение на Rust (раз уж за него зацепились) отставало от 1-го места по очкам менее чем вдвое. И именно в этом контексте я и написал, что в таких условиях решает не язык, а конкретные оптимизации.

                Именно про это я и говорю, но. Конкретные оптимизации зависят от языка и я, так же, сказал почему.

                Я спорю именно с тем, что оптимизации — это какая-то вещь в себе. Нет. Для оптимизаций нужны возможности, в том числе, со стороны языка.

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


                1. TargetSan
                  20.09.2017 17:54

                  Это был не я.

                  Да, точно. Извиняюсь.


                  Именно про это я и говорю, но. Конкретные оптимизации зависят от языка и я, так же, сказал почему.

                  Я спорю именно с тем, что оптимизации — это какая-то вещь в себе. Нет. Для оптимизаций нужны возможности, в том числе, со стороны языка.

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

                  Эээ… ну да, я согласен. Засим, думаю, ветку можно прикрывать.


      1. robert_ayrapetyan
        20.09.2017 17:06
        +2

        Алгоритмы вообще не решали.
        Все упиралось в сеть и хаки с epoll. Я в финальном был в конце (43-м), после пилюли с epoll(0) — сейчас в песочнице на 25 (учтите, что почти все ее приняли после слива в чате в последний день).
        Если бы я знал о пилюле epoll(0) в день финала, мое решение было бы на 7-ом месте. Но так нельзя говорить, т.к. еще 25 человек из топ-50 могут сказать то же самое.


        1. TargetSan
          20.09.2017 17:45

          Мне понравилась идея, предложенная на следующий хайлоад. Постепенно поднимать RPS. Выиграет тот, кто дольше всех проживёт, не выходя за SLA.


        1. phponelove
          20.09.2017 17:57
          -2

          Все упиралось в сеть и хаки с epoll.

          Почему же хаки? Знание и использование особенностей работы.


          1. mayorovp
            20.09.2017 18:25
            +2

            Потому что в реальных задачах epoll(0) — это не оптимизация, а напрасное пережигание электричества.


            1. phponelove
              20.09.2017 18:36
              -1

              А jvm — это не напрасное прожигание электричества? А пхп — это не напрасное прожигание электричества? А жсон, хттп и прочее — это что? Это такое же напрасное прожигание электричества.

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

              А подобные кастыльные парсеры жсона так же используются в реальных задачах? А подобные роутеры так же используются в реальных задачах? Что же вы так избирательны.

              Я не знаю причины по которым вы говорите то, что говорите. Но я предполагаю то, что причина тут явно не в реальных задачах, не в электричестве, а в неком недовольстве/обиде на тех, кто этот «хак» знал.


              1. phponelove
                20.09.2017 18:55

                Ведь вы же измеряли цпу-время разных решений

                Ведь вы же НЕ измеряли цпу-время разных решений. Естественно.


              1. phponelove
                20.09.2017 19:46
                -2

                Кто смелый — кто сможет аргументировать за минусы? А то получается странно. Минусы есть, а ответов нет. В такой ситуации ведь не скажешь, что «я просто несогласен, а ответ уже итак дан другим участником и я с ним согласен». Почему вы поступаете так несправедливо?


                1. robert_ayrapetyan
                  20.09.2017 20:02
                  +4

                  С точки зрения сожжения CPU — безусловно и epoll(0) и пхп с jvm жгут его с КПД разной степени паршивости. Но из прикладных соображений — я представляю решение на пхп в проде, но с epoll(0) уже нет, даже банально по ssh туда влезть не удастся. Я не минусил (и не умею ;)


                  1. phponelove
                    20.09.2017 20:23
                    -1

                    С точки зрения сожжения CPU — безусловно и epoll(0) и пхп с jvm жгут его с КПД разной степени паршивости.

                    Это не ответ. Было определено два тезиса: «Потому что в реальных», «а напрасное пережигание электричества».

                    Что из этого следует? А то, что всё что не из множества «реальных задач» и всё, что «напрасно пережигает электричество» неприменимо и является хаком.

                    Мною были выдвинуты контрпримеры — на что последовало молчания. Если не можете в аргументацию своих тезисов, то зачем это вообще начинать?

                    я представляю решение на пхп в проде

                    Опять же. Вы нарушаете условие. Применимы-ли в проде парсинг жсона и хттп так, как это сделано в некоторых(почти всех) решениях? Нет. Ну дак зачем вы суёте сюда то, чем решения заведомо не соответствует.

                    Так же, не важно то, что вы представляете, а что нет. Пхп просто так жрёт электричество? Жрёт. Под критерий определённый автором первоначального утверждения подходит? Подходит. Всё остальное — отношения к делу не имеет.

                    Вы можете начать рассуждать о том, что рабсила дороже электричества, как какие-то иные критерии дороже, но. За это решение покупается производительность. Точно так же, как в пхп покупается что-то другое.

                    Никто не определил, что производительность — это «неважный» критерий, а что-то иное важный.

                    но с epoll(0) уже нет, даже банально по ssh туда влезть не удастся.

                    Не верно. Епул долбит не во всех потоках одновременно, а даже если во всех — есть планировщик. Никакой ссш у вас не сломается.

                    Ну и вообще, кто вас сказал о том, что epoll(0) заканчивается на захардкоренном нуле? Ничего вам не мешает считать время проведённое в обработчике и на основе данной статистике рулить этим аргументом.

                    Я не минусил (и не умею ;)

                    Я говорю не про вас, а про тех, кто минусует без аргументации.


                    1. robert_ayrapetyan
                      20.09.2017 20:38
                      +4

                      >Это не ответ. Было определено два тезиса: «Потому что в реальных», «а напрасное пережигание электричества».
                      Это не я отвечал если что ).
                      Мой тезис был такой — epoll(0) это хак. И конечно это хак! Смотрите — одно и то же решение: 43 место без epoll(0), 7 с epoll(0), изменена одна строка в коде! Это по вашему филигранная работа и особенности? Мдмашка в чистом виде.
                      >Опять же. Вы нарушаете условие. Применимы-ли в проде парсинг жсона и хттп так, как это сделано в некоторых(почти всех) решениях? Нет. Ну дак зачем вы суёте сюда то, чем решения заведомо не соответствует.
                      Тут и комментировать нечего. Конечно применимы, в реальных хайлод все это сплошь и рядом.
                      >Не верно. Епул долбит не во всех потоках одновременно, а даже если во всех — есть планировщик. Никакой ссш у вас не сломается.
                      Во всех где вызываешь epoll(0) (а это все ядра, иначе зачем он вам вообще нужен в любом виде в реальном проде?). Из личного опыта знаю, что когда все ядра заняты на 100% (а именно это происходит) доступ по ssh становится невозможным.

                      И вообще вы какой-то нервенный… Судя по нику — из-за расклада с PHP в highloadcup-е? Ну так там и нода утерлась, не переживайте вы так.


                      1. phponelove
                        20.09.2017 23:45
                        -1

                        Это не я отвечал если что ).

                        Это неважно. Вы отвечаете в том контексте, которые определили до(после вас) вас. В нём же отвечал и я. Менять условия нельзя.

                        Мой тезис был такой — epoll(0) это хак. И конечно это хак! Смотрите — одно и то же решение: 43 место без epoll(0), 7 с epoll(0), изменена одна строка в коде!

                        Ну дак перечитайте то — на что я отвечал и кому. Зачем менять условия?

                        Вам не нравится одна строчка? Ну что поделать.
                        Это по вашему филигранная работа и особенности? Мдмашка в чистом виде.

                        Это не работа — это знание особенной того окружения, в котором работаете.

                        Тут и комментировать нечего. Конечно применимы, в реальных хайлод все это сплошь и рядом.

                        Тогда это решение точно так же применимо в хайлоаде. Профит даёт.

                        Ну и не понятно так же. Всё это соответствует критериям, которые определили выше. И определил их не я. Вы точно так же оспорили это: habrahabr.ru/post/338268/#comment_10428330

                        В чём причина ваших ко мне претензий?

                        Во всех где вызываешь epoll(0) (а это все ядра, иначе зачем он вам вообще нужен в любом виде в реальном проде?).

                        Епул не обязательно долбить из всех потоков.

                        Из личного опыта знаю, что когда все ядра заняты на 100% (а именно это происходит) доступ по ssh становится невозможным.

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

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

                        И вообще вы какой-то нервенный… Судя по нику — из-за расклада с PHP в highloadcup-е? Ну так там и нода утерлась, не переживайте вы так.

                        Не из-за этого. Я уже описал причины.


                        1. TargetSan
                          21.09.2017 00:29
                          +1

                          К слову, epoll(0), или BUSY_WAIT приводит к тому, что еполл сразу возвращается, независимо от кол-ва сработавших событий. Это приводит к тому, что текущий поток крутится в чём-то наподобие спинлока вместо того, чтобы сразу отдать остатки кванта. И да — это даёт прирост — но только в очень конкретных сценариях. И таки да, в нормальном продакшене так не делают, т.к. вместо прироста будет просадка.


                          1. phponelove
                            21.09.2017 01:25
                            -1

                            К слову, epoll(0), или BUSY_WAIT приводит к тому, что еполл сразу возвращается, независимо от кол-ва сработавших событий.

                            Я знаю о том, что произойдёт при epoll(0). Хотя формулировка не верна — кол-во событий на ожидание не влияет — любой событие будет епул.

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

                            Кому? Дяди Васи? Что конкурирует с епуллом по ЦПУ? Неужели обработчик евентов в том же треде(как это делается во всех реализация, что я видел)?

                            И таки да, в нормальном продакшене так не делают, т.к. вместо прироста будет просадка.

                            Какие ваши доказательства?


                            1. mayorovp
                              21.09.2017 10:54

                              Кому? Дяди Васи? Что конкурирует с епуллом по ЦПУ? Неужели обработчик евентов в том же треде(как это делается во всех реализация, что я видел)?

                              Прежде всего — блокирующие операции, которые вынуждены выполняться в фоновых потоках. Скажем, у gethostbyname нет асинхронного варианта. Надо либо использовать сторонние библиотеки — либо выносить вызовы в отдельные потоки.


                              Далее — любые отложенные задачи. Которые могли бы нормально выполниться в периоды простоя (например, в 3-4 ночи по времени основной аудитории).


                              Служебные программы. Например, мониторинг. Или уже упомянутый тут ssh.


                              А еще процессор может уменьшить свое энергопотребление если никто не крутит его в вечном цикле.


                              1. phponelove
                                21.09.2017 11:24
                                -1

                                Прежде всего — блокирующие операции, которые вынуждены выполняться в фоновых потоках.

                                Какие такие операции и в каких таких потоках? Поподробнее об этом.

                                Далее — любые отложенные задачи. Которые могли бы нормально выполниться в периоды простоя (например, в 3-4 ночи по времени основной аудитории).

                                Им ничего не мешает выполнятся — планировщик устроен так, что он даёт равное время на исполнения всем процессам/потокам. Вам об этом сообщили, но вы продолжаете всё игнорировать и гнёте свою линию.

                                При этом — захардкоренный ноль — это лишь дыра в реализации участников, которые не смогли/не захотели это реализовать иначе.

                                Банальное ev = epoll_wait(..., !ev * timeout); решает почти указанные проблемы, а если пойти чуть дальше — это решает все проблемы.

                                Хак — это как максимум реализация участников, а не сам ноль в таймауте.

                                Служебные программы. Например, мониторинг. Или уже упомянутый тут ssh.

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

                                А еще процессор может уменьшить свое энергопотребление если никто не крутит его в вечном цикле.

                                А ещё процессор может уменьшить своё энергопотребление, если не использовать пхп, либо жаву. Дальше что? И опять же — вы продолжаете все мои доводы игнорировать. Зачем?

                                Если есть какие-то критерии по энергопотребленю — с них и надо начинать. А с них никто не начинал и о них никто не говорил. Вы их откуда-то достали и сделали каким-то определяющими.

                                Да и как минимум, перед тем как заявлять — надо посчитать сколько потребляет ЭЭ те же решения на пхп на той же нагрузке, а потом сравнить — стоит ли это меньше, чем пару часов epoll(0). Хотя опять же, данная ситуация — ваши выдумки. Это свойство не epell(0), а отдельных реализация. И я уже говорил почему.


                                1. mayorovp
                                  21.09.2017 12:44
                                  -1

                                  Хак — это как максимум реализация участников, а не сам ноль в таймауте.

                                  Бинго!


                                  1. phponelove
                                    21.09.2017 13:22
                                    -4

                                    Есть нюансы.

                                    Потому что в реальных задачах epoll(0)

                                    Это мой промах, конечно. Забыл вас спросить о том, что такое epoll(0) для того, чтобы защитить себя от подобного.

                                    Дело в том, что из epoll(0) следует именно epoll(0). Вы говорили именно об epoll(0), а не захардкоривании там нуля. И это очень просто доказывается, в частности, этим:

                                    Если бы я знал о пилюле epoll(0) в день финала, мое решение было бы на 7-ом месте.

                                    Т.е. если бы epoll(0) был бы реализован не путём захардкоренного нуля, а иначе( допустим, как показал выше я) — вы бы получили тот же результат. Но — без всех тех свойств, которые вы приписывали epoll(0). Это мат.

                                    Именно результат вы определили за хак, именно то, что позволяет его добиться — вы определили за хак. Позволяет не ноль, не реализация, а именно epoll(0). Реализация — это нюансы.

                                    И теперь, когда я на это вышел — вы переобулись, но это неправильно и некрасиво.


                                    1. mayorovp
                                      21.09.2017 13:27

                                      А теперь прочитайте еще раз, кто именно писал разные комментарии. Спойлер: у вас был не один оппонент.


                                      1. phponelove
                                        21.09.2017 13:57

                                        А теперь прочитайте еще раз, кто именно писал разные комментарии. Спойлер: у вас был не один оппонент.

                                        Не верно. Если вы не определяете контекст — он экспортируется из ветки выше. Такие правила. Если я что-то написал в каком-то контексте — нельзя от него(вам) откреститься и сказать «я это не писал». Так это не работает. Я отвечал в рамках него. Вы отвечали точно так же в рамках него и никак иначе.

                                        Если проще. Вы попытались наделить мою цитату своими смыслами, которых в ней не было. В частности:

                                        Потому что в реальных задачах epoll(0) — это не оптимизация, а напрасное пережигание электричества.

                                        Вы взяли определение epoll(0) у автора ветки — иного быть не может. Своего вы не дали.

                                        Вот я дал своё определение — разграничил epoll(0) и паттерн его использования. Поэтому теперь я могу использовать и то и то отдельно.

                                        Вы же этого не сделали — со всеми вытекающими. И теперь это выглядит обычной манипулцией.


                                        1. mayorovp
                                          21.09.2017 14:02

                                          Из контекста лично мне очевидно, что речи про алгоритм выбора тайм-аута для epoll не шло. Просто в какой-то момент часть участников услышала про нулевой тайм-аут, заменила у себя тайм-аут нулевым — и за счет этого резко поднялась в рейтинге.

                                          Это и есть хак.


                                          1. phponelove
                                            21.09.2017 14:55
                                            -1

                                            Из контекста лично мне очевидно, что речи про алгоритм выбора тайм-аута для epoll не шло.

                                            Про алгоритм выбора таймаута речи и не идёт.

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

                                            Точно так же они могли узнать про что угодно.

                                            Ваши обвинения были в чём? В неприменимости нулевого таймаута — это не так. Нулевой таймаут не является хаком.

                                            И результат не является хаком. Я так же об этом писал с ссылками на инициатора ветки.

                                            Хаком назывались именно ПОЛУЧЕННЫЕ РЕЗУЛЬТАТЫ, а не метод их получения. И вы сами же этому вторили своими заявлениями про неработоспособность нулевого таймаута.

                                            Это и есть хак.

                                            Это подмена понятий.

                                            Нулевой таймаут — не хак. Нулевой таймаут — оптимизация. Нулевой таймаут не ограничивается захардкоренным нулём. Изначально определялось критерием хака РЕЗУЛЬТАТ. Вы выше это повторили.

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

                                            Просто задача ограничить цпу-время не стояло — этим никто и не заморачивался. Я не верю в то, что участники из топ10 не осилили бы реализовать это иначе.

                                            Поэтому такая реализация — это лишь свойство задачи. Вернее задача не требовала по иному её решать. Вы же взяли совершенно левые условия и начали с ними что-то качать. Так это не работает.

                                            Люди создавали решения в рамках конкретных условий. И я уже доказал то, что реализовать это и для ваших условий труда не составляло. С тем же результатом.


          1. MikailBag
            20.09.2017 18:26

            del


    1. AterCattus
      20.09.2017 12:49
      -1

      Что есть "чистый"? Моя ж гошка на 11 месте.


      1. robert_ayrapetyan
        20.09.2017 17:01

        Я твою и имел ввиду (сейчас в песочном 7-ом «грязная» с хаком на С++). В финале твоя на 11, без вопросов.


        1. AterCattus
          20.09.2017 20:49

          Ах вон оно что. Я уже как-то не слежу. Надо будет глянуть, что там за хак.


          1. robert_ayrapetyan
            20.09.2017 20:54

            Хм, я теперь думаю что (Go -> C++) — это чувак полностью переписал на С++, а не Го с хаком на С++ )


            1. AterCattus
              20.09.2017 21:04

              Возможно)
              Или там func main() { C.realization() } :)


  1. mrobespierre
    20.09.2017 02:59
    +5

    Автор — молодец, нашёл ошибку там, где другие и не заметили. Даже и с учётом того, что Rust — всё ещё язык экзотический и хорошо разбирались в нём из 45 тыс. просмотревших 45 в лучшем случае. И тем не менее сенсации не получилось:

    1. Голый net/http не используется в highload проектах на golang
    2. Этот тезис я писать не буду, а то ребята из Mail.ru обидятся :-D


    1. humbug Автор
      20.09.2017 04:30
      +9

      Голый net/http не используется в highload проектах на golang

      Хороший тезис! hyper тоже не самая быстрая библиотека. Именно поэтому я тестил на древней версии rustc с дешевым hyper, а не пытался заоптимизировать код по самое не могу.


      Изначальный посыл автора оригинальной статьи был хорош: для каждого языка взять "стандартный компонент" для работы с http, пострелять в него и посмотреть на оверхед рантайма и кривизну библиотеки/языка. Вот мы и посмотрели.


      1. dmbreaker
        20.09.2017 10:09
        +7

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


    1. akzhan
      20.09.2017 22:05

      лайк за второй пункт.


      я изначально и написал читаемый пример на Crystal, а страдать уйней не стал )


  1. beduin01
    20.09.2017 07:12
    +7

    Заголовок не соответствует содержанию. Правильно было назвать статью так: «Mail.ru опять обобралась». Куда этим людям поисковик делать если они публично позорятся в каждой публикации.


    1. quantum
      20.09.2017 09:15
      +1

      А это были одни и те же люди?


      1. akzhan
        20.09.2017 22:06

        не все так просто )


  1. 0xd34df00d
    20.09.2017 07:41
    +6

    Ради интереса попробовал хаскелевский Snap. 12.8 мс на запрос против гошных 12.5 на моей машине. Написать что ли тоже мини-статью? :)


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


    1. 0xd34df00d
      20.09.2017 07:51
      +3

      И это даже как-то пессимистично. Уменьшил число процессов до двух с автодетекта, получил 10.5 мс для хаскеля. Очень неплохо.


  1. sshmakov
    20.09.2017 08:57
    +5

    Может быть глупость спрошу, я этих языков не знаю, но где в Go обработка not_found и проверка метода?


  1. gobwas
    20.09.2017 10:07
    +1

    Привет! Спасибо за найденную ошибку, это действительно fail. Безусловно, это нужно будет исправить и обновить результаты замеров.


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


    Самое главное – статья 2015 года не называлась "какой язык быстрее". Она была о выборе языка программирования, и производительность написанных серверов была лишь одним из критериев. Это написано прямо в самом первом ее абзаце.


    Если иметь это в виду, то разница, которую вы получили с исправлением, никак не влияет на наш выбор Go. Более того, в тестах так же есть обработчики без логики (GET /), в которых Rust был (и наверное есть) быстрее.


    1. Bonart
      20.09.2017 11:47
      +8

      Самое главное – статья 2015 года не называлась "какой язык быстрее". Она была о выборе языка программирования, и производительность написанных серверов была лишь одним из критериев. Это написано прямо в самом первом ее абзаце.

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


      1. gobwas
        20.09.2017 12:03
        -4

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


        1. Bonart
          20.09.2017 13:16
          +7

          это наименее субъективная вещь

          В которой у вас объективный эпик фейл.


          Скажите, о какой дезинформации вы говорите?
          "производительность написанных серверов была лишь одним из критериев"

          Фраза в кавычках — дезинформация в чистом виде. Производительность была главным критерием, а не просто "одним из".


          Если иметь это в виду, то разница, которую вы получили с исправлением, никак не влияет на наш выбор Go

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


          1. gobwas
            20.09.2017 13:48

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


            Если бы ваше предположение о "главном критерии" было бы верным, то почему бы нам, например, не выбрать C или ассемблер?


            1. Bonart
              20.09.2017 14:26
              +2

              Если бы ваше предположение о "главном критерии" было бы верным, то почему бы нам, например, не выбрать C или ассемблер?

              Очевидно потому, что они не удовлетворяли критериям отсева перед финальным сравнением. Вот финалистов вы отранжировали по производительности.


              Как можно называть дезинформацией то, что субъективно?
              "Содержание субъективных оценок было намеренно опущено в этой статье, дабы не делать очередной наброс и не провоцировать холивар. Тем более что если бы такие оценки не учитывались, то по критериям, указанным выше, результат остался бы прежним."
              Если иметь это в виду, то разница, которую вы получили с исправлением, никак не влияет на наш выбор Go

              1. В статье ранжирование было по производительности,
              2. После исправлений первое и второе места поменялись,
              3. Разница не поменяла выбора, для которого якобы достаточно информации из статьи.

              Проблема не в результате выбора, а в том, что после исправлений он перестал быть очевиден из статьи. Такие дела.


    1. humbug Автор
      20.09.2017 12:09
      +14

      Как бы она не называлась, ущерб русскоязычному сообществу Rust вы нанесли. Нравится вам Go — пишите на нём. Кто ж спорит.


      1. gobwas
        20.09.2017 12:23
        -3

        Не пойму вашей позиции. Мы выбрали язык, на котором вот уже два года пишем сервисы. На момент выбора – Go в почте не было. На момент выбора – большинство специалистов писали на C, Perl и JavaScript. Как я уже сказал, независимо от ошибки, которую вы нашли, мы бы все равно выбрали Go. И не потому, что выбор предвзят, а по совокупности разных критериев. Вы хотите, чтобы мы передумали и начали писать на Rust?


        1. UA3MQJ
          20.09.2017 12:32
          +6

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


          1. PSIAlt
            20.09.2017 12:36
            -1

            Выходит, человек поделившись своим трудом нанес ущерб сообществу Rust и навредил тем, кто решает что выбрать, я правильно понял?


            1. Crandel
              20.09.2017 12:38
              +10

              Это больше похоже на подтасовку результата под Go


              1. PSIAlt
                20.09.2017 12:48
                -4

                Не драматизируйте. Это больше похоже на баг. Который кстати никто не заметил, что характеризует размер и активность сообщества rust.


                1. Crandel
                  20.09.2017 13:05
                  +8

                  Вы только доказываете, что была подтасовка в сторону Go, ведь там не было таких детских багов(всем известно, что регулярки медленные в любом языке), соответственно, автор не разобрался с Rust, а просто наваял побыстрому кода для большего хайпа.


                  1. PSIAlt
                    20.09.2017 13:19
                    -7

                    Про хайп не знаю, я не спец в этом. Вряд ли хайп помог бы автору починить проблему на проде.
                    Про баги — там могло не быть детских багов по двум причинам: а) автор знает Go намного лучше чем Rust (это плюс в сторону выбора Go) и б) Go не допускает глупых ошибок (это плюс в сторону выбора Go).


                    1. Bonart
                      20.09.2017 13:21
                      +2

                      В этом случае не стоит проводить тесты производительности вообще.
                      Что делаешь — делай хорошо.


                      1. gobwas
                        20.09.2017 13:50
                        +1

                        Все верно. Пишешь код – пиши без багов!


                        1. Bonart
                          20.09.2017 14:31
                          +4

                          Ерничать не нужно.
                          Если производительность не влияет на выбор, не надо включать ее в сравнение.
                          Если влияет, надо обеспечить минимальный уровень качества тестов.
                          Вы не обеспечили, причем за счет простой ошибки.
                          Если уровень знаний о расте настолько низок — его не должно было быть в финальном сравнении.


                    1. humbug Автор
                      20.09.2017 13:59
                      +1

                      Ну да, круто засовывать всё в main и утверждать, что Go не допускает глупых ошибок.


      1. PSIAlt
        20.09.2017 12:45
        -8

        Про ущерб сообществу это просто смешно. Оно слабое, в том числе по этой причине выбор был сделан правильно. Поясню:
        В изначальной статье 3им пунктом было «Большое сообщество, позволяющее быстро найти ответы на вопросы». Т.е. сильное сообщество нужно, чтобы делать задачи без лишних головняков, а также сильное ревью и так далее. Так вот, это сообщество нашло эту кажется простую ошибку спустя только 2 года. Выходит, проблема была и до статьи, что только добавляет очков к Go.


        1. TargetSan
          20.09.2017 12:56
          +11

          Так вот, это сообщество нашло эту кажется простую ошибку спустя только 2 года. Выходит, проблема была и до статьи, что только добавляет очков к Go.

          То есть если я найду в любой паблик статье про произвольный язык ошибку, я смогу говорить, что у него плохое сообщество — потому что не просматривает все статьи и не ищет в них ошибки с остервенением? Вот это реально был бы фанатизм.


        1. akzhan
          20.09.2017 22:09
          +2

          В времена оны сообщество Golang было в России отнюдь не на порядок сильнее сообщества Rust. И уж тем более сообщества C++11(14, 17).


          Вообще, сейчас современный C++ идеален (не ущербен по сравнению с Go).


          1. 0xd34df00d
            21.09.2017 00:20
            +2

            «Идеален» и «не ущербен по сравнению с Go» — это всё-таки не синонимы, как бы не хотелось сторонникам Go :)


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


      1. TargetSan
        20.09.2017 12:50

        Это вы как-то палку перегибаете. Если одна статья с бенчмарками, пусть и от Мэйл.Ру, способна нанести серьёзный вред сообществу — я уж и не знаю.


        1. humbug Автор
          20.09.2017 14:01
          +8

          Действительно, как? Мне на самом деле кинули ссылку на статью как аргумент. Да, я в 2015 году пропустил эту статью, но тот человек — нет. И у него сформировалось определенное мнение на тему Go vs Rust.


          1. TargetSan
            20.09.2017 14:18

            Проблема в том, какое определённое мнение ваши реплики, а также Crandel, сформируют о самом сообществе Rust у присутствующих здесь. СпокойнЕе надо быть. Тем более, что ребята из мэйл.ру не встали в позу, а спокойно, как адекватные люди, сказали "Упс, да, ошибочка".


            1. ozkriff
              20.09.2017 14:20
              +4

              Очень поддерживаю что перегиб по эмоциям.


              Любишь раст, люби и https://www.rust-lang.org/en-US/conduct.html :)


            1. Crandel
              20.09.2017 14:23
              +7

              Тем более, что ребята из мэйл.ру не встали в позу, а спокойно, как адекватные люди, сказали "Упс, да, ошибочка".

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


            1. Bonart
              20.09.2017 14:34
              +5

              Автор из мыла именно что встал в позу, заявив о неизменности результата в статье даже после исправления.


              1. gobwas
                20.09.2017 16:20
                -2

                Вы ошибаетесь.


  1. Akdmeh
    20.09.2017 10:14
    +7

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


  1. acmnu
    20.09.2017 10:26
    -1

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


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


    1. Bonart
      20.09.2017 11:52
      +3

      Претензии по части синтаксисиа скорее к расту.
      У го отсуствие обобщений, присутсвие null, обязательный сборщик мусора вызывают куда больше вопросов, чем любые проблемы с синтаксисом.


      1. TargetSan
        20.09.2017 12:17
        +2

        А кстати какие претензии к Rust по синтаксису?


      1. acmnu
        20.09.2017 18:22
        -1

        Да я неудачно выразился. Скорее синтаксис и возможности.


    1. UA3MQJ
      20.09.2017 12:26

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


    1. akzhan
      20.09.2017 22:11

      попробуйте Crystal, не факт, что вам подойдет, да и до первой версии еще несколько месяцев, но прямо глоток свежего воздуха.


  1. UA3MQJ
    20.09.2017 10:47

    Ждем от mail.ru замеры статьи про Go инструменты для того, чтобы подрубаться к приложению в продакшене под нагрузкой, всякие там интроспеции, профилирование, поглядеть куда утекает память. Вроде бы это pprof.
    А то, что Go на hello world http показывает высокий RPS все уже и так знают.


    1. AterCattus
      20.09.2017 12:56

      Таких материалов и так куча.


  1. Antervis
    20.09.2017 10:51

    Гораздо важнее вопрос синтаксиса. И тут к обоим языкам огромное количество притензий.

    Претензий по части синтаксиса и к их конкурентам (системные яп) много


    1. ozkriff
      20.09.2017 11:31
      +3

      "Системные яп" — после всех срачей вокруг "системности" go, точно хорошая идея продолжать так говорить? Понятно же, что на практике все под системностью языка что-то свое понимают и это провоцирует споры на пустом месте.


      1. khim
        20.09.2017 17:08
        +3

        Системный язык — это то, на чём пишется система (феноменально, да?), то есть то, что не привязано ни к какому конкретному языку. И, собственно, системный язый язык у нас тут один — это Rust. Ни на чём другом вы ни библиотечку для Fortran'а, ни модуль в ядро Linux'а не напишите.

        Будут ли их реально на Rust писать? Хороший вопрос — поживём, увидим. Но ни на Scala, ни на Go их написать нельзя. Вернее можно «на спор» — но это уже будет в чистом виде «вырезание гланд автогеном через задний проход».

        Go в этом смысле немного похож на пресловутые Лисп-машины: в отличие от многих других языков поддержка в виде C ему «для жизни» не нужна — но и поддержать какой-либо другой язык, кроме титулярного, они не могут.


        1. mayorovp
          20.09.2017 17:18
          -3

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


          1. khim
            20.09.2017 19:02
            +3

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

            Так-то можно любыми словами называть всё, что угодно — только тогда общаться тяжело становится. Системная оболочка, возможно, её может быть отнесена к системе (хотя кто и где видел системную оболочку, написанную, скажем, на Prolog'е?), а вот уже системные утилиты и средства разработки — точно нет. Потому что ими человек пользуется, а не другие программы.


            1. mayorovp
              20.09.2017 19:13

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


              1. khim
                20.09.2017 19:31

                Тем не менее администрированием занимается человек, а не других программы, как правило.


                1. mayorovp
                  20.09.2017 19:46

                  Но он этим занимается для того, чтобы обеспечить работоспособность тех самых других программ.


                  1. khim
                    20.09.2017 20:04

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


            1. MacIn
              20.09.2017 19:18

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

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

              А вы материал по своей же ссылке читали? Видимо, нет:
              Отнесение того или иного программного обеспечения к системному условно, и зависит от соглашений, используемых в конкретном контексте. Как правило, к системному программному обеспечению относятся операционные системы[?], утилиты[?], системы программирования[?], системы управления базами данных[?], широкий класс связующего программного обеспечения.


              1. khim
                20.09.2017 19:31
                +1

                Всю жизнь трансляторы и компоновщики, интерпретаторы командной строки и т.п. входили в системное ПО, а тут на тебе — уволили.
                Именно так. Потому что если их включать, то становится непонятно что вообще туда не будет попадать. В английской версии написано более аккуратно: по историческим причинам в некоторых огранизациях термин «системный программист» используется по отношению к людям, которых более правильно было бы назвать «системными администраторами» — в этом случае программное обеспечение, которые эти люди используют, тоже могут быть названы «системным» [...] В некоторых публикациях в категорию системного программного обеспечения также относятся средства для разработка (такие как компилятор, компоновщик, или дебаггер).

                «По историческим причинам» — это как раз и означает, что «да — было, помним, но… пора бы об этом и забыть».


                1. MacIn
                  20.09.2017 19:41
                  -4

                  Удивительного ничего нет: в нашей, русскоязычной школе программирования сложилась своя терминология.
                  «исторические причины» указаны по поводы термина системный программист/системный администратор; мы же с вами о том, что такое системное ПО. Здесь же указано: «В некоторых публикациях в категорию системного программного обеспечения также относятся средства для разработка (такие как компилятор, компоновщик, или дебаггер).»
                  Вы приводите цитату, указывающую вариативность и берете оттуда только ту часть, что вам в строку.

                  Потому что если их включать, то становится непонятно что вообще туда не будет попадать

                  Браузер, при помощи которого мы с вами общаемся. Текстовый редактор, музыкальный проигрыватель и так далее. Все прикладное ПО.


                  1. khim
                    20.09.2017 20:09
                    +3

                    Браузер, при помощи которого мы с вами общаемся.
                    Да ладно. А с помощью чего я кодревью делаю, как вы думаете?

                    Текстовый редактор
                    Используется для правки всё того же кода.

                    музыкальный проигрыватель
                    Позволяет мне размечать файлы при создании образов операционки.

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

                    Все прикладное ПО.
                    Может быть использовано для разработки. Даже игры — мы с их помощую скорость JIT'а меряем.


                  1. khim
                    20.09.2017 20:15

                    Собственно ровно в той статье в википедии текстовые редакторы прямо так и недвусмысленно отнесены к системному ПО. Так что если уж берётесь отличать системные текстовые редакторы от несистемных — приводите критерии.


                1. mayorovp
                  20.09.2017 19:50
                  -3

                  Именно так. Потому что если их включать, то становится непонятно что вообще туда не будет попадать.

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


                  1. khim
                    20.09.2017 20:12
                    +3

                    Ага. А потом ещё отменим разделение на тёплые и холодные цвета, твёрдые и мягкие предметы и вообще — отменим все прилагательные нафиг. А чё? Кто-то ж перепутать может!


        1. ozkriff
          20.09.2017 19:00
          +1

          Системный язык — это то, на чём пишется система (феноменально, да?), то есть то, что не привязано ни к какому конкретному языку.

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


          модуль в ядро Linux'а… Будут ли их реально на Rust писать? Хороший вопрос — поживём, увидим

          Знаю по крайней мере про этот (обучающий?) пример: https://github.com/tsgates/rust.ko


          1. khim
            20.09.2017 19:09
            +2

            Ну вот Goшники как-то не очень согласны с этим определением, дофига где Go называется системным языком — от того поначалу было много срачей про ЦА языка и его применимость вообще.
            Это их проблемы. Для того, чтобы Go можно было назвать системным языком нужно дать такое определение, которое было бы
            1. Включающим в себя язык Go (что очевидно).
            2. Логичным (давайте не будем извращаться и придумывать определения типа «язык программирования системный, если в его названии не более трёх букв»).
            3. Не включающим в себя какой-либо распространённый язык программирования (а иначе зачем вообще такое понятие, которое все языки скопом записывает в системные?).

            Вот с пунктом номер 3 — обычно жёсткий напряг.


            1. ozkriff
              20.09.2017 19:20

              Вот ведь написал изначально как раз что бы в тысячный раз эта скучная фигня не повторялась, блин.


  1. amarao
    20.09.2017 11:28
    +5

    Rust ощущается как язык с порогом вхождения. Нужно повернуть мозг в правильную позицию, чтобы заработало. И этот порог — вовсе не в странных 'закорючках, :: которые &mut местами :(i32) смущают. Закорючки бытро учатся. А вот лежащая в основе модель памяти требует капитального перетряхивания сознания, причём как при переходе с Python/ruby/php/perl, так и при переходе с C.


    1. snuk182
      20.09.2017 14:16
      +3

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


      1. amarao
        20.09.2017 17:46
        +1

        Точно не проще. Она может быть «проще в практическом применении» если учитывать время на отладку, но она точно не проще для понимания.

        Попробуйте объяснить, что такое str (не &str!) с точки зрения программы.
        lifetimes, ownership & borrow — всё это центральные абстракции памяти rust'а, поскольку они определяют момент выделения/очищения памяти.

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


        1. snuk182
          20.09.2017 18:16
          +1

          Про сишную не скажу, но вот многострадальный JSR 133 я понимаю и помню ровно пять минут после прочтения — рассказываемые там вещи слишком эфемерны и теоретизированы. Практика же к ним находится в не то чтобы очень простой и понятной книге Гётца, но даже эта книга несоизмеримо проще написанного почти юридическим с точки зрения понимания простыми смертными языком JSR 133. И вот по сравнению с джавовским сотонизмом модель памяти Rust легка и понятна с полуслова. Всего три постулата:
          1. Не твоё — не трогай.
          2. Дал попользоваться — жди когда вернут.
          3. Беспорядочный доступ запрещен. Нужно меняться между потоками — вот каналы. Нужно делиться между потоками — вот мьютексы. Хочешь настоящего беспорядка — unsafe и ССЗБ.
          4. (опционально) Компилятор Rust — друг. Это понимание приходит со временем , особенно после общения с javascript.
          С str вообще все просто — это обычный массив в хранении, но с определенными правилами в обработке. В случае литерала данные массива зашиты в постоянную память, наружу торчит толстая ссылка (указатель + размер массива), которая жива от скобки до скобки, или пока перемещающие функции ее не съедят.


          1. amarao
            20.09.2017 21:10
            +1

            То что вы показываете это не модель памяти, а принципы использования.

            Сишная модель памяти базируется на арифметрике указателей и стеке. У раста к этому добавляется понятие владения.


        1. khim
          20.09.2017 19:20
          +4

          но сишная модель грубее и проще
          Вы это серьёзно? Чем memory_order_acq_rel от memory_order_seq_cst отличатеся — не напомните?

          Сайд-эффекты её при этом ужасающи, но для объяснения на пальцах — сильно проще.
          Нифига не проще. Проще она была в далёком прошлом — когда процессор в системе был один и кеширования в нём не было предусмотрено вообще. В современном же мире сишная модель (почти ничем не отличающаяся от того, что железо предоставляет, на самом деле) — ужасающе сложна и 99.99% программистов на C её не понимают от слова «вообще». Отсюда и «сайд-эффекты».


        1. Halt
          20.09.2017 19:51
          +2

          str — это безразмерный (unsized) тип, представляющий строковое значение, а &str — ссылка на него. Примерно как void и void* в Си, только без костылей.

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

          Вероятно потому, что с void сишник знакомится в младенчестве и просто принимает на веру, что «надо писать void, когда функция не возвращает значения, а void* это… ну просто указатель, когда не знаем, на что указываем». В итоге человек к этому привыкает и перестает об этом думать.


          1. amarao
            20.09.2017 21:13

            Аналогия с void мне нравится, однако: void не подразумевает чего-то. То есть я могу сказать, что функция возвращает void (т.е. ничего), я могу делать операции с указателями на void, но чего-либо с типом void в C нет. А в rust'е каждая константная строка — это str. Я с трудом себе могу представить декларацию void-с-содержимым в Си. В расте такое есть (let a = «hello»).


            1. BlessMaster
              20.09.2017 21:18

              удалено


              1. amarao
                20.09.2017 21:27

                Правильно. А справа, после знака равно — str. И когда я делаю slice от String, у меня тоже str. Так что же такое str?

                Пока что лучшая аналогия, которую я придумал, звучит так: str — это как земля (в контексте недвижимости). Можно передать права на неё, можно выкопать из неё всю почву, построить и снести дом, но нельзя переместить землю, нельзя увезти с собой. Она просто есть. На неё можно показывать, в ней можно хранить, можно запрещать или разрешать ходить по ней, но это и всё.


            1. 0xd34df00d
              21.09.2017 00:22

              То есть я могу сказать, что функция возвращает void (т.е. ничего)

              В С можете, в математике нет. Если функция не возвращает ничего (вернее, если возвращаемый тип не населён), то вы не можете её вызвать.


              но чего-либо с типом void в C нет

              И это иногда немножко бьёт в темплейтах :(


              1. amarao
                21.09.2017 12:02

                Ох, тут начинается что-то крайне любопытное. Вот у нас есть функция sin(1/x). У нас есть функция lim x->0 f, которая принимает f и возвращает её предел к 0.

                Что возвращает lim x->0 sin(1/x)?


                1. mayorovp
                  21.09.2017 13:02

                  lim x->0 sin(1/x) возвращает особое значение "результат операции не определен" или "операция недопустима". В программировании его можно представить как NaN, как исключение или как None в монаде Optional.


                  1. amarao
                    21.09.2017 16:52
                    -1

                    Вы рассказываете, что оно в программировании возвращает. Можно ещё exception сделать.

                    А что оно в математике «возвращает»? Ничего. Тот самый void.

                    Другой пример. Выражение «пусть а равно нулю» какое значение возвращает? Тоже никакого.


                    1. mayorovp
                      21.09.2017 17:05
                      +2

                      А что оно в математике «возвращает»? Ничего. Тот самый void.

                      Вы путаете тип и значение. Тип данных — это множество всевозможных значений. Выражение lim x->0 f как функция от f может вернуть любое вещественное число или "ничего" (на самом деле там еще три вида бесконечности может получиться, но для простоты их пропустим). При подстановке конкретного параметра sin (1/x) получается второй вариант, но это не означает что тип возвращаемого значения — "ничего". Тип возвращаемого значения — R | { NaN }, множество действительных чисел расширенное на 1 элемент.


                      Выражение «пусть а равно нулю» какое значение возвращает?

                      Вообще говоря, это не выражение, это определение. Но если рассматривать его как операцию присваивания и забыть про монаду IO, то такое выражение может вернуть только 1 значение — "успех операции". Поэтому тип такого выражения — Unit, в памяти компьютера он занимает 0 байт.


              1. mayorovp
                21.09.2017 12:58

                Вы путаете void в понимании Си и в понимании ФП. Да, в ФП под void обычно подразумевается ненаселенный тип, что-то чего в принципе не существует.


                В Си, C++ и C# void ведет себя скорее как нормальный тип размера 0 байт — у него есть ровно 20=1 возможное значение, и именно этого значение называют "ничего".


                В Java void ведет себя странно: будучи примитивным типом, он ведет себя так же как и в Си, но при "упаковке" до Void его единственное значение пропадает (остается только общее для всех ссылочных типов значение null). К счастью, синтаксис языка не позволяет делать такую упаковку, а потому это несоответствие остается лишь теоретической странностью.


                И да, соглашусь что было бы неплохо разрешить использование void в темплейтах или дженериках


                1. phponelove
                  21.09.2017 13:30

                  В Си, C++ и C# void ведет себя скорее как нормальный тип размера 0 байт — у него есть ровно 20=1 возможное значение, и именно этого значение называют «ничего».

                  Из чего именно следует то, что он ведёт себя именно так? Это какие-то другие Си, а в моих void — это не значение.


                  1. mayorovp
                    21.09.2017 13:38

                    Потому что функция, которая возвращает ненаселенный тип, не может существовать (если только она не принимает ненаселенный тип). А функцию, которая принимает ненаселенный тип, невозможно вызвать.


                    Поскольку в Си функции могут как возвращать void, так и принимает его в параметрах — это определенно не ненаселенный тип, а что-то другое.


                    1. phponelove
                      21.09.2017 14:36
                      -3

                      Потому что функция, которая возвращает ненаселенный тип, не может существовать (если только она не принимает ненаселенный тип).

                      Я не про это спрашивал.

                      Поскольку в Си функции могут как возвращать void, так и принимает его в параметрах — это определенно не ненаселенный тип, а что-то другое.

                      Это так же не ответ. Я спрашивал не то — как не ведёт себя void, а то — почему вы решили, что он ведёт себя именно так, как вы описали.

                      Давайте попроще. Вы написали «void ведет себя скорее как красный». Вас спросили «почему вы решили, что воид — это красный. В моих си он не красный, а чёрный».

                      И вы ответили что? Оно не может быть зелёным потому что это не как «бла-бла». Поскольку в Си функция не как «бла-бла» — это не зелёный, а что-то другое.

                      Но вам не говорили о том, что оно зелёное. Вас спросили — почему вы говорите о том, что оно скорее красное. Всё просто.

                      А по поводу

                      Поскольку в Си функции могут как возвращать void, так и принимает его в параметрах

                      Нет. Никто и никак принимать void не может. void в аргументах не означает, что функция принимает какой-то воид.

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

                      Существо понятие «ничего» и существует тип. Ничего. У ничего нет значений. Ничего нельзя никак и нигде использовать. Это поведение, которое не соответствует другим типам.

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

                      А теперь включаем логику. Когда значение в функции, либо где-либо ещё появляется? Правильно — в момент его использования. До того момента — значение ничего не значит и ни на что не влияет.

                      Тем самым вызов функции void f(); В результате имеет тип воид, а значит не имеет значения. Ничего не мешает чему-то не иметь значения и мы можем это использовать, но мы не может использовать значение.

                      Именно так и работает void в си. Именно поэтому функции с void существуют. Существуют тогда, когда мы не пытаемся использовать значение void. Его просто нет.

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


                      1. mayorovp
                        21.09.2017 15:06
                        +2

                        В теории типов существует лишь два объекта, про которые можно сказать что они означают «ничего». Это ненаселенный тип, у которого нет значений — и тип нулевого размера, у которого 1 значение.

                        Я не говорил что void в Си — это в точности один из них, разумеется это не так. Но void гораздо больше похож на второй вариант чем на первый.


                        1. phponelove
                          21.09.2017 15:14

                          В теории типов существует лишь два объекта, про которые можно сказать что они означают «ничего». Это ненаселенный тип, у которого нет значений — и тип нулевого размера, у которого 1 значение.

                          И воид — это именно тот тип, у которого нет значений.

                          Но void гораздо больше похож на второй вариант чем на первый.

                          Вот я и спрашиваю — чем же он похож. Я объяснил чем он похож на первый. Теперь ваша очередь.


                          1. mayorovp
                            21.09.2017 15:22

                            1. phponelove
                              21.09.2017 15:28

                              Это не ответ и я уже объяснял почему. Подобное меня удивляет.

                              А по поводу темы — ниже я пруфцанул из стандарта. Т.к. апеллировать к логике и пониманию перестало иметь смысл. Хотя сомневаюсь, что и до этого оно имело смысл.


                          1. mayorovp
                            21.09.2017 15:28
                            +1

                            Вот вам еще аргументы.

                            1. Размер ненаселенного типа — минус бесконечность. Это очень странный тип данных.

                            2. Когда вызывается функция которая принимает void — на стеке выделяется 0 байт для ее аргументов.

                            3. Когда вызывается функция которая возвращает void — на стеке резервируется 0 байт для возвращаемого значения.

                            4. В языке существует тип «указатель на void». Для ненаселенного типа такая конструкция абсурдна.


                            1. phponelove
                              21.09.2017 15:51

                              Я уже сказал, что никаких аргументов у вас нет.

                              1. Размер ненаселенного типа — минус бесконечность. Это очень странный тип данных.

                              Никакого размера у void нету. Мимо.

                              2. Когда вызывается функция которая принимает void — на стеке выделяется 0 байт для ее аргументов.

                              Опять же мимо. Никакие стэки к си отношения не имеют и ничего не выделяется. Срочно стоит почитать букварь.

                              3. Когда вызывается функция которая возвращает void — на стеке резервируется 0 байт для возвращаемого значения.

                              Аналогично.

                              Я даже не знаю плакать или смеяться. Чем отличаются «выделение 0 байт» от «не выделяется вообще»? К чему тут вообще ноль?

                              callabi находится за пределами языка и вообще это деталь реализации. С таким же успехом я могу сказать, что в вашем ФП у void не бесконечный размер и точно так же выделяется ноль.

                              Что из это следует? Да ничего. Отсутствие аргументов.


                              1. mayorovp
                                21.09.2017 15:57

                                Я даже не знаю плакать или смеяться. Чем отличаются «выделение 0 байт» от «не выделяется вообще»? К чему тут вообще ноль?

                                Ничем не отличается.


                                С таким же успехом я могу сказать, что в вашем ФП у void не бесконечный размер и точно так же выделяется ноль.

                                Не можете. Потому что, как я уже говорил, в ФП функцию принимающую Void нельзя вызвать, а возвращающую Void — нельзя создать. Вы не найдете областей памяти в работающей программе, которые можно было бы классифицировать как значение ненаселенного типа.


                                1. phponelove
                                  21.09.2017 16:15

                                  Ничем не отличается.

                                  Хорошо. Сколько должно выделяться под никакое значение? Чёткий ответ.
                                  Не можете. Потому что, как я уже говорил, в ФП функцию принимающую Void нельзя вызвать

                                  А что с ней делать? Смотреть на неё?

                                  Для чего вообще нужен void?

                                  Кстати — как там дела с NaN? Интегрируется ли он в логику ФП? И каким образом.
                                  Вы не найдете областей памяти в работающей программе, которые можно было бы классифицировать как значение ненаселенного типа.

                                  Прям как в Си.

                                  Как удобно врать и манипулировать. Говорим о типе а потом бам — о значении.


                                  1. mayorovp
                                    21.09.2017 16:18

                                    Как удобно врать и манипулировать. Говорим о типе а потом бам — о значении.

                                    Это вы так делаете, не я.


                                    Раз пошли переходы на личность — дискуссию заканчиваю.


                                    1. phponelove
                                      21.09.2017 16:22
                                      -2

                                      Это вы так делаете, не я.

                                      Где же?
                                      Раз пошли переходы на личность — дискуссию заканчиваю.

                                      Где же?


                                  1. 0xd34df00d
                                    21.09.2017 20:12
                                    +2

                                    А что с ней делать? Смотреть на неё?

                                    Смотреть. Использовать как элемент построения доказательства (или контрпримера) в пруверах. Всякое такое. В реальном продакшен-коде таких фукнций нет.


                                    Для чего вообще нужен void?

                                    В С или в языках с более целостной системой типов?


                                    Кстати — как там дела с NaN? Интегрируется ли он в логику ФП? И каким образом.

                                    Как одно из значений типа Double, например.


                                    1. phponelove
                                      21.09.2017 20:40
                                      -5

                                      Смотреть. Использовать как элемент построения доказательства (или контрпримера) в пруверах. Всякое такое. В реальном продакшен-коде таких фукнций нет.

                                      Каким образом её можно использовать в пруферах, если позвать нельзя?

                                      В С или в языках с более целостной системой типов?

                                      В ФП.

                                      Как одно из значений типа Double, например.

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

                                      Как именно нан интегрируется в модель ФП, в функции и значения с т.з. математики?

                                      Я, всё же, до сир пор не понимаю чем не устраивает void в Си. Наверное только тем, что он не такой как в хаскеле. Все свойство, которые определил человек выше у него есть.

                                      По мне так логика функций в Си намного более полная, нежели в ФП.

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

                                      В моём понимании функция — это набор операций над аргументами и результат не обязательно должен быть выражен в результате — он может быть выражен и в аргументах — путём их модификации.

                                      Я может какой-то альтернативно-одарённый и не способен понять всей мощи ФП, но смотря на всё это — когда мы можем нарушать свои правила во имя поддержания языка. Ведь в рамках этих правил он попросту бесполезен. А после выдавать эти правила за какую-то истину. По мне — это глупо. Как вам — не знаю.

                                      Т.е. я вижу причины по которым воид сделан иначе, но я не вижу причин того — что воид с Си какой-то не такой. Он такой же.

                                      Либо человек как-то неправильно это объяснял, либо я как-то не понял. Но вроде понял. У воида нет значений. Воид использоваться не может. Отсутствие значения не наделяет воид каким-то значением, либо не делает его значением.

                                      И неважно какое там значение — тип это не значение. Зачем подменять понятия и спрашивать с типа свойств значения? Ничего непонятно.


                                      1. 0xd34df00d
                                        21.09.2017 21:45
                                        +1

                                        Каким образом её можно использовать в пруферах, если позвать нельзя?

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


                                        В ФП.

                                        В ФП Void почти не используется. Даже отдельной библиотекой в том же хаскеле сделан, например: void.


                                        Как именно нан интегрируется в модель ФП, в функции и значения с т.з. математики?

                                        Как и любой другой элемент типа Double. У NaN есть представление, в конце концов, и в алгебру даблов он вполне себе вписывается.


                                        Я, всё же, до сир пор не понимаю чем не устраивает void в Си.

                                        Если вкратце, тем, что вы не можете написать void a = void {};.


                                        В моём понимании функция — это набор операций над аргументами и результат не обязательно должен быть выражен в результате — он может быть выражен и в аргументах — путём их модификации.

                                        Про это я уже писал рядом про сайд-эффекты.


                                        Я может какой-то альтернативно-одарённый и не способен понять всей мощи ФП, но смотря на всё это — когда мы можем нарушать свои правила во имя поддержания языка. Ведь в рамках этих правил он попросту бесполезен. А после выдавать эти правила за какую-то истину. По мне — это глупо. Как вам — не знаю.

                                        Я это не распарсил.


                                        1. phponelove
                                          21.09.2017 22:25

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

                                          Её же нельзя вызвать — как я её могу вызвать?

                                          Как и любой другой элемент типа Double. У NaN есть представление, в конце концов, и в алгебру даблов он вполне себе вписывается.

                                          Оно не вписывает никуда. Вы просто экспортировали логику из ieee754 в даблы. И я спрашиваю не про логику даблов, а про математику и ФП.

                                          Хотя я заранее знаю ответ — никак, но всё же. Вдруг он есть, а я просто не знаю.

                                          Если вкратце, тем, что вы не можете написать void a = void {};.

                                          Естественно — это не имеет смысла. Логика операции = — присваивание значения, которого у воида нету.

                                          Опять же — каким тогда образом функцию с ФП с аргументов воидом вызвать нельзя, если записать в воид воид можно? Вы уже там определитесь. Является ли воид значением, либо нет.

                                          Про это я уже писал рядом про сайд-эффекты.

                                          Вы писали обратное тому, что пишу тут и там я.

                                          Я это не распарсил.

                                          Если проще. Реальный мир состоит из NaN, сайд-эффектов и прочего, что в логику чисто функциональную не влезает. Выше я писал о конкретных противоречиях в ваших выкладках.

                                          Таким образом всё это ФП-великолепие просто не работает и мы обязаны интегрировать туда наны, сайдэффекты и прочее. Иначе ФП не имеет смысла.

                                          Но при этом мы декларируем что? Что логика ФП правильная, а какая-то иная не правильна. При этом логика ФП за рамками самого ФП( в рамках реального мира) несостоятельна.

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

                                          Т.е. как происходит. У нас там снизу не чистота, но мы верим в то, что у нас чистота. Как?

                                          Это у меня и вызывает вопросы. Как то, что не может существовать само по себе можно выдавать за правильную, самодостаточную концепцию?


                                          1. 0xd34df00d
                                            22.09.2017 02:03
                                            +1

                                            Её же нельзя вызвать — как я её могу вызвать?

                                            Хороший вопрос. Функцию Void -> Void — никак. Функцию a -> Void — можете. Просто вы её написать не можете. Язык с totality checker'ом это вообще не проглотит, а в хаскеле любой тип также населён значением undefined, либо, пардон за сленг, бесконечной рекурсией (которая на самом деле одна из реализаций undefined), либо чем-нибудь таким. В любом случае, конструктивно вызвать вы и такую функцию не сможете.


                                            Таким образом всё это ФП-великолепие просто не работает и мы обязаны интегрировать туда наны, сайдэффекты и прочее. Иначе ФП не имеет смысла.

                                            В реальном мире NaNов нет, кстати. Но это так.


                                            Выше я писал о конкретных противоречиях в ваших выкладках.

                                            Я их как-то не увидел, и до сих пор не вижу.


                                            Что логика ФП правильная, а какая-то иная не правильна.

                                            Первична не логика ФП, а логика, ну, некоторой математической теории. ФП тут может возникать лишь как модель этой логики, не более.


                                            У нас там снизу не чистота, но мы верим в то, что у нас чистота. Как?

                                            Hask is not a category, увы.


                        1. phponelove
                          21.09.2017 15:22

                          Пошел за пруфами в стандарт:

                          The void type comprises an empty set of values; it is an incomplete object type that
                          cannot be completed.


                          Стандарт считает так же. Вариант номер раз.


                          1. mayorovp
                            21.09.2017 15:31
                            -1

                            Это показывает лишь намерения создателей стандарта но не то что у них фактически получилось.


                            1. humbug Автор
                              22.09.2017 00:59
                              +1

                              Объясню доходчивей.


                              В C объявление void f(void) — это не объявление функции, которая принимает void и возвращает его, это объявление набора инструкций, у которого есть адрес с названием f. И всё.


                              Допустим, мы пишем такой С код:


                              //clang 3.8.0
                              
                              #include  <stdio.h>
                              
                              f(x) {
                                 printf("%d\n", x);
                              }
                              
                              int main(void)
                              {
                                  f(42);
                                  return 0;
                              }

                              И да, это валидный C код. Оно компилируется и работает.


                              Что за херня? Как это возможно?

                              А вот так. По-дефолту, если не указывать тип, он равен int.
                              И вот мы пришли к тому, о чем говорил наш функциональщик: к стеку. Если мы хотим "функцию", которая ничего не возвращает, опустить тип нельзя. На стеке будет выделяться sizeof(int) байт(а т.к. в моем примере в конце функции я не сделал return VALUE_OF_ANY_INT, то функция вернёт мусор, что делает использование ее возвращаемого значения неопределенным поведением). А сишники очень любят экономить и оптимизировать. Поэтому в C ввели синтаксический мусор в виде void. При этом void* — это не указатель на void, это свой особый тип, при попытке разадресации которого вы получите ошибку:


                              Compiler Error: 'void*' is not a pointer-to-object type 

                              Поэтому halt выше сказал:


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

                              И перестаньте думать о сишных функциях как о функциях вообще. C — это кроссплатформенный ассемблер, функции — это именованый адрес инструкции.


                              1. mayorovp
                                22.09.2017 05:55
                                -3

                                Почему я должен думать о void как о «синтаксическом мусоре» если все его свойства кроме одного прекрасно объясняются тем что это тип нулевого размера?


                                1. humbug Автор
                                  22.09.2017 08:26

                                  Какие свойства? Какое исключение?


                                  1. mayorovp
                                    22.09.2017 08:35
                                    -1

                                    Все то, что я уже перечислял в комментариях.


                                    Исключение — невозможность создания переменной типа void.


                                    1. humbug Автор
                                      22.09.2017 09:09

                                      Ну а мое высказывание "синтаксический мусор" объясняет все свойства и исключение.


                                      1. mayorovp
                                        22.09.2017 09:19

                                        Нет, с таким подходом каждое свойство должно объясняться отдельно.


                                    1. Caefah
                                      22.09.2017 09:34
                                      -2

                                      Это не мешает писать на Си всё. От ядер операционных систем до «кошечек». Операционка на Java?, на Rust?, на Go? Три раза хе хе хе!!!


                                      1. mayorovp
                                        22.09.2017 09:37

                                        Это вы к чему сказали? Я что, где-то утверждал обратное? Какое отношение загадки типизации имеют к распространенности языка?


                                        1. Caefah
                                          22.09.2017 09:41
                                          -1

                                          Сорри, хабра искажает картину комментирования. Это был ответ на другой пост.


                          1. 0xd34df00d
                            21.09.2017 20:24

                            Давайте с другой стороны. Пусть мощность множеств A и B — 0. Какова мощность множества функций из A в B? В силу некоторых соображений (матлогических и категориальных, в частности) эта мощность равна единице. То есть, существует единственная такая функция.


                            Пусть теперь мы вместо B (явно объявленное возвращаемое значение функции) рассмотрим возвращаемое значение вместе со всеми сайд-эффектами (у нас же не чистый язык, в конце концов), которое есть декартово произведение B на некоторое другое множество. Декартово произведение пустого множества с любым множеством пусто, поэтому мощность множества void(void) функций даже с учётом сайд-эффектов должна быть равна единице, что, как мы знаем, не так, их поболе будет.


                            1. phponelove
                              21.09.2017 21:00
                              -2

                              Декартово произведение пустого множества с любым множеством пусто, поэтому мощность множества void(void)

                              Какие-то манипуляции. Мы взяли аргумент и результат. Потом каиким-то образом к ним добавились сайд-эфекты. С т.з. вашей логики сайд-эфекты находятся за рамками вашей логики и ваша логика для них не работает.

                              Точно так же их будет поболее при любых других аргументах — из этого ровным счётом ничего не следует. Вы получите те же результаты и без воид.

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

                              Каким образом мы проводим какие-то произведения хрен пойми чего с хрен пойми чем — мне так же неясно. Из этого произведения ровным счётом ничего не следует и все следствие из него не имеет смысла.

                              Сайд-эффекты это не что-то левой — это всё входит в множество аргументов/возвратов функции.

                              Точно так же всё это зафейлится и на void(1bit, 64bit) — либо мы за множество возьмём оба аргумента? Тогда то же будет и с сайд эффектами.

                              В любом случае — я не понимаю что из этого должно следовать?


                              1. 0xd34df00d
                                21.09.2017 22:09

                                Формальное теоретико-множественное рассуждение.

                                Какие-то манипуляции.

                                Ясненько. Понятненько.


                                1. phponelove
                                  21.09.2017 22:45
                                  -2

                                  Ясненько. Понятненько.


                                  Ваше определение чего-то чем-то не стоит ничего. Вы можете назвать что угодно чем угодно и от этого оно не станет этим просто потому, что вы это так назвали.

                                  Вы попытались играть со мною в логику — выдавая свои определения за какие-то формальные рассуждения. Вас спросили — каким образом вы сайд эффекты записали в аргументы/возврат функции. Ведь в рамках вашей логики функция имеет только один выход — возврат. Иного не дано.

                                  А то, что с сайд-эффектами — это совершенное иное определение, нежели то, что вы использовали вначале.

                                  Это и есть манипуляции. Дыры в понимание подбиваются под существующую картину мира. Из этого не выйдет ничего.

                                  Всё это маскируется под «формальными рассуждениями», которые состоят на самом деле из банального жонглирования понятиями.

                                  В любом случае — ладно. Я в очередной раз для себя определил потолок способностей евангелистов.


                                  1. 0xd34df00d
                                    22.09.2017 02:13
                                    +3

                                    Ваше определение чего-то чем-то не стоит ничего.

                                    Моё определение чего? Классической наивной теории множеств или теории множеств Цермело-Френкеля? Широко известной теории типов? Ну там, я не знаю, Бенджамина Пирса почитайте, что ли, я, к сожалению, не такой умный, чтобы самостоятельно все эти глупости выдумывать.


                                    Вы попытались играть со мною в логику — выдавая свои определения за какие-то формальные рассуждения.

                                    Более того, вообще говоря я могу построить произвольную систему определений, наделить её некоторыми аксиоматическими отношениями между определениями и построить на этом теорию. Будет вполне формально. Математика, собственно, так работает.


                                    Вас спросили — каким образом вы сайд эффекты записали в аргументы/возврат функции. Ведь в рамках вашей логики функция имеет только один выход — возврат.

                                    Нет. Написал специально для этого случая: «Пусть теперь мы вместо B (явно объявленное возвращаемое значение функции) рассмотрим возвращаемое значение вместе со всеми сайд-эффектами (у нас же не чистый язык, в конце концов), которое есть декартово произведение B на некоторое другое множество.». Вот то самое другое множество и есть множество всех сайд-эффектов.


                                    А то, что с сайд-эффектами — это совершенное иное определение, нежели то, что вы использовали вначале.

                                    Нет. Начиная от монадического формализма заканчивая тупейшим декартовым произведением.


                                    Что до последних ваших трёх абзацев, коли хотите пассивную агрессию — получите пассивную агрессию: во-первых, так вот и перестаньте подбивать свои дыры в понимание, а вместо этого прочтите какую-нибудь базовую книгу по матлогике (вроде лекций Верещагина и Шеня), а затем догонитесь упомянутым ранее Пирсом, коли такие дискуссии вам интересны. Во-вторых, специалисты вроде вас с евангелистами вроде меня едва ли пересекутся где-то в реальной жизни, так что не думаю, что ваше определение потолка будет иметь какие-то сайд-эффекты.


                                    Да и вообще, моя любимая картинка в тему:


                                    Тыц


                1. 0xd34df00d
                  21.09.2017 20:04

                  Вы путаете void в понимании Си и в понимании ФП. Да, в ФП под void обычно подразумевается ненаселенный тип, что-то чего в принципе не существует.

                  Так я вроде сразу написал: «В С можете, в математике нет.»


                  В Си, C++ и C# void ведет себя скорее как нормальный тип размера 0 байт — у него есть ровно 20=1 возможное значение, и именно этого значение называют «ничего».

                  Ну да, сиподобный void — это как () в каком-нибудь хаскеле.


            1. humbug Автор
              22.09.2017 00:31

              операции с указателями на void

              Это тавтология. Попробуйте разадресовать void* и получите ошибку компиляции:


              Compiler Error: 'void*' is not a pointer-to-object type 


          1. phponelove
            21.09.2017 01:45

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

            Поподробнее об этом, пожалуйста. Что именно становится плохо?

            Вероятно потому, что с void сишник знакомится в младенчестве и просто принимает на веру

            Некой мистической «строгостью» понимание не ограничено, логика не ограничена.

            «надо писать void, когда функция не возвращает значения, а void* это… ну просто указатель, когда не знаем, на что указываем»

            А ещё надо писать void, когда функция не принимает аргументов. Давайте поиграем в игру.

            void определяет отсутствие результата, либо возврата. Как хотите это называйте. Что такое тип у указателя? Это тип возвращаемого операцией разыменования значения.

            Что такое void * — это указатель для которого нет операции разыменования. *(void *) == void, то же самое что void f() {}; f(). Результата нет.

            Мы не не знаем на что указываем — мы ни на что не указываем. «указатель указывает» — это детский садик. Это как функция у которой нельзя взять результат, так это — указатель, у которого так же нельзя взять результат.

            int f(); и int * p; — они идентичны. Только у одной операция скобочки, а у второй звёздочка.

            Тут скорее всего проблема в том, что как и сишник принимает на веру — так и представления о си — это вера. И то, что у кого-то есть вера — из этого не следует то, что без веры в си нет логики.


            1. phponelove
              21.09.2017 01:57

              Ах да, забыл про арифметику. Опять же это сайзоф поверх типа «до» звёздочки. И sizeof(void) в итоге.


  1. Akon32
    20.09.2017 11:37
    +3

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


  1. RPG18
    20.09.2017 12:30
    +1

    Я скептически отношусь к подобным тестам, когда берут любые две реализации сервера, без изучения их работы. Т.к. есть такие штуки как zero-copy, пулы памяти, пулы потоков, ленивые вычисления и т.д.


    1. Halt
      20.09.2017 12:44
      +1

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


      1. RPG18
        20.09.2017 13:07
        +2

        Hyper из коробки в Rust?


        1. Halt
          20.09.2017 19:57

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


        1. BlessMaster
          20.09.2017 20:00
          +1

          Как бы это ни было смешно, но буквально "из коробки", как и всё, что на crates.io :-)


  1. nuald
    20.09.2017 12:45
    +8

    Внесу свои пять копеек. Я портировал все оригинальные тесты на современные библиотеки, и замерил производительность на своем макбуке. Скажу сразу, что я еще не закончил, плюс макбук — далеко не серверная платформа. Тем не менее, предварительные результаты уже готовы: github.com/nuald/simple-web-benchmark#preliminary-results

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


    1. Buggins
      20.09.2017 15:31
      +1

      Прислал pull request — код на языке D (vibe-d).

      app.d
      import vibe.d;
      import std.regex;
      
      auto reg = ctRegex!"^/greeting/([a-z]+)$";
      
      shared static this()
      {
          auto settings = new HTTPServerSettings;
          settings.port = 3000;
      
          listenHTTP(settings, &handleRequest);
      }
      
      void handleRequest(HTTPServerRequest req,
                          HTTPServerResponse res)
      {
          if (req.path == "/")
              res.writeBody("Hello, World!", "text/plain");
          else if (auto m = matchFirst(req.path, reg))
              res.writeBody("Hello, " ~ m[1], "text/plain");
      }
      


      1. Buggins
        20.09.2017 15:36

        Немного быстрее, чем Go.
        Для запуска нужны компилятор D (DMD или LDC) и DUB.
        Компилировал DMD. LDC должен давать более быстрый код.

        Форк.


      1. Buggins
        21.09.2017 10:37

        На github.com/nuald/simple-web-benchmark появились результаты тестирования D на macbook.
        D получился даже медленней node-js.

        Потестировал D (vibe.d) по сравнению с Go.
        На Windows 7 x64 — vibe.d собранный DMD под x86 чуть быстрее Go только если выбрана конфигурация vibe.d libevent. Иначе в два раза медленней.

        На Linux x86_64 — vibe.d собранный DMD и в default конфигурации и в libevent показывает 45K запросов в секунду, a Go — 50K запросов. Но зато D использует 90% CPU, a Go — 120%.

        Теоретически сборка Vibe.d с помощью компилятора LDC вместо DMD должна показать лучшие результаты. Проверить пока не получилось.


    1. IncorrecTSW
      20.09.2017 16:54
      +3

      go version go1.9
      rustc 1.22.0-nightly

      hey -n 200000 -c 256 -t 10 http://127.0.0.1:3000
      Go
      Average: 0.0040 secs
      Requests/sec: 63371.1408

      Rust
      Average: 0.0036 secs
      Requests/sec: 68601.3122


  1. AterCattus
    20.09.2017 12:59

    Ну это ж был скорее тест реализации библиотеки регулярок, нежели http сервера. А в go оно очень так себе.


    1. Laney1
      20.09.2017 15:51
      +2

      регулярки в Go выполняются в среднем медленнее чем в других языках, зато всегда за линейное время. Так и было задумано (Робом Пайком)


      1. AterCattus
        20.09.2017 16:01

        Да, я в курсе, конечно, про линейное время.
        Но в тесте сравнивается просто производительность типичной регулярки (не хитро продуманной).


  1. aliev
    20.09.2017 14:23
    +7

    Только стал Go изучать, а он уже не торт.


    1. RinatUsmanov
      20.09.2017 14:44
      -10

      Расслабьтесь.

      У Go есть преимущества которые пока мало кто может оспорить:
      1. Простота языка. Легко понять как свой код написанный год назад, так и код другого программиста.Т.е. низкий порог входа.Соответственно легче поддерживать проекты. Соответственно низкая стоимость поддержки. (Значит бизнес будет его использовать и далее)
      2. Синтетические тесты это лишь меряние «письками». даже если Go уступает по этим тестам другим языкам, это не значит что он хуже или наоборот лучше. Это лишь означает что где то в каких то задачах он уступает. Никто не может сказать куда придет 2 версия. Все может кардинально поменяться в сторону производительности в нужном синтетическом тесте ))).


      1. Antervis
        20.09.2017 15:59
        +4

        всё то же самое можно сказать про python


      1. 0xd34df00d
        20.09.2017 19:15
        +4

        Простота понимания кода — не единственный фактор, влияющий на стоимость поддержки. Есть ещё и стоимость внесения изменений, а тут чем более строгий компилятор и система типов, тем лучше (от раста до всяких хаскелей, да).


    1. Buggins
      20.09.2017 16:05

      Попробуй D.
      Киллер фича go — goroutines есть и в D — fibers.
      Плюс многое другое, чего в Go нет.


    1. taroved
      20.09.2017 23:09

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


  1. halpro
    20.09.2017 17:37
    +1

    Тем, кто сидит на Java или C# смотрят на Go. Ну простите, все равно приложение на Go будет жрать больше памяти и CPU по сравнению с приложением на C++ или Rust. GC — главный тормоз этих языков!
    А плюсовики ждут релизов 1.0 всех фреймворков и IDE (и плагинов) для Rust! И безболезненно перейдут на Rust и будут смеяться над мусоросборными языками.


    1. khim
      20.09.2017 19:22
      +1

      Ну простите, все равно приложение на Go будет жрать больше памяти и CPU по сравнению с приложением на C++ или Rust.
      Памяти — да, CPU — нет. Главная проблема GC не в том, что оно вносит задержки, а в том, что эти задержки плохо предсказуемы. Go в этом смысле весьма неплох.


      1. phponelove
        20.09.2017 19:32
        +1

        Памяти — да, CPU — нет.

        Память в современном, да и в любом другом мире, не отделима от CPU. ЦПУ читает память и время затраченное на её чтение/запись/ожидание прямо пропорционально кол-ву этой самой памяти, при прочих равных. А они равные.

        Главная проблема GC не в том, что оно вносит задержки

        Задержки стоят ЦПУ, внезапно. Сколько их — одна большая, либо много маленьких — неважно. Хотя много — естественно дороже.


        1. khim
          21.09.2017 13:55

          Память в современном, да и в любом другом мире, не отделима от CPU.
          Отделима, отделима, ещё как отделима. 10 лет назад самый быстрый CPU — это примерно 5GHz, сегодня — плюс-минус столько же. Правда их побольше стало, но не в 100 раз. А память в «тяжёлых» системах выросла со 128GiB до 128TiB (не так давно этот рубеж штурмовали).

          Так что транжирить память — плохо, но транжирить CPU — ещё хуже.

          Задержки стоят ЦПУ, внезапно. Сколько их — одна большая, либо много маленьких — неважно.
          Для компилятора, рендерера, любой «пакетной» задаче — да, важно когда вся задача будет решена. Для сервера или интерактивной программы — ой как важно. Скорость CPU-то расти перестала! Ожидать что завтра задержки из миллисекундных станут микросекундными больше нельзя…


          1. phponelove
            21.09.2017 15:08

            Отделима, отделима, ещё как отделима.

            Нет.

            10 лет назад самый быстрый CPU — это примерно 5GHz, сегодня — плюс-минус столько же. Правда их побольше стало, но не в 100 раз. А память в «тяжёлых» системах выросла со 128GiB до 128TiB (не так давно этот рубеж штурмовали).

            Вы либо не понимаете того, о чём вам пишут, либо делаете это специально. Вам говорили не об объёмах памяти, а необходимости траты ЦПУ на на работу с ней(памятью).

            Так же — вы имели ввиду под ЦПУ — не железяку, а процессорное время. Теперь вы пытаетесь подменять понятия. Зачем?

            ЦПУ читает память и время затраченное на её чтение/запись/ожидание прямо пропорционально кол-ву этой самой памяти, при прочих равных. А они равные.

            Вам тут чётко и ясно определили связь между ЦПУ и памятью. И из этого выводится то, что имеет ввиду под ЦПУ.

            Так что транжирить память — плохо, но транжирить CPU — ещё хуже.

            Не так что.

            Для компилятора, рендерера, любой «пакетной» задаче — да, важно когда вся задача будет решена. Для сервера или интерактивной программы — ой как важно. Скорость CPU-то расти перестала! Ожидать что завтра задержки из миллисекундных станут микросекундными больше нельзя…


            Вы что сказали?

            Памяти — да, CPU — нет.

            Всё это в контексте оверхада ГЦ по сравнению с ручным управлением памятью.

            Вам объяснили, что это неверно. И ответ существует именно в контексте потребления ЦПУ ГЦ. И вам так же сказали, что задержки — это ЦПУ-время. И неважно какие это задержки по продолжительности — в сумме их столько же. А на самом не столько же, а больше(го-вариант). Ведь вызов ГЦ это не только полезная работа, но оверхеды на сам вызов и уже с ним + пакетная обработка быстрее + всё это загаживает кешей больше и прочее и прочее).

            Ваши попытки рассуждать о каком-то там влиянии этой задержки на разные кейсы — к теме не относятся. Об этом разговора не было.


            1. khim
              21.09.2017 17:06
              +1

              ЦПУ читает память и время затраченное на её чтение/запись/ожидание прямо пропорционально кол-ву этой самой памяти, при прочих равных. А они равные.
              Вам тут чётко и ясно определили связь между ЦПУ и памятью.
              Вот тут прямо и чётко написали чушь. Главный и притом неверный тезис «а они равные» упомянув невнятной скороговоркой в конце.

              Нет. Они неравные. Это уже давно всё исследовано: чем больше вы даёте GC памяти, тем меньше ему нужно кучу сканировать и тем быстрее он работает. Примерно на 500% скорость GC сравнивается с аккуратным «ручным» распределением памяти, а если дать памяти ещё больше — то может быть и быстрее.

              Вам объяснили, что это неверно.
              Не обьяснили, а заявили. Причём заявили голословное — без ссылок на исследования. Я-то надеялся, что вы вышеупомянутую статью читали, раз берётесь обо всём этом размышлять.

              И неважно какие это задержки по продолжительности — в сумме их столько же.
              Вы действительно не понимаете что чушь здесь написали? Это же азы всей теории! В случае с GC затраты времени не просто зависят от того, сколько у вас «лишней» памяти, а очень сильно от этого зависят. Как и в случае с обычным распределением памяти, впрочем (локальная память для потока в каком-нибудь tcmalloc'е тоже ведь требует некоторого «запаса»).


              1. phponelove
                21.09.2017 17:53

                Удобство.


              1. phponelove
                21.09.2017 18:19
                -2

                Вот тут прямо и чётко написали чушь. Главный и притом неверный тезис «а они равные» упомянув невнятной скороговоркой в конце.

                Где? Вы берёте мою цитату и разбираете, с явным указанием что там чушь.

                Начнём, пожалуй. Я отвечал на:

                Ну простите, все равно приложение на Go будет жрать больше памяти и CPU по сравнению с приложением на C++ или Rust.


                Каким образом разница в потреблении памяти стала определяться только наличием ГЦ? Сколько по умолчанию в го отдаётся памяти ГЦ? Сколько по памяти стоит насувать во все объекты счётчики ссылок?

                Т.е. никаким ГЦ контекст не ограничивался и это всё не более, чем попытка врать.

                Это уже давно всё исследовано: чем больше вы даёте GC памяти, тем меньше ему нужно кучу сканировать и тем быстрее он работает.

                К ГЦ это не имеет никакого отношения. То же самое работает и для обычных аллокаторов.

                Нет. Они неравные.

                Опять же.
                И неважно какие это задержки по продолжительности — в сумме их столько же.

                Ни о каких объёмах памяти для ГЦ я не говорил. Я говорил о паузах. Очередная попытка врать.

                Это уже давно всё исследовано: чем больше вы даёте GC памяти, тем меньше ему нужно кучу сканировать и тем быстрее он работает.

                Ничего не исследовано. Го/жаву вам в руки и вперёд срывать покровы. Можете начать с хайлоадкаппа, а закончить какой-нибудь in-memory database.

                Примерно на 500% скорость GC сравнивается с аккуратным «ручным» распределением памяти, а если дать памяти ещё больше —

                Не верно. Это результаты протухшие — раз. Для 3-4бенчмарков из spec, которым а) никто не видел, б) вы не воспроизведёте их результаты.

                Ни о каком аккуратном режиме речи не шло — никаких свидетельств о том какое он — в статье нету. Это всё не более, чем бла-бла.

                Ну и да, ручная аллокация не заканчивается на маллоке. Заканчивается она им только в подобных «исследованиях».

                то может быть и быстрее.

                Опять же — бла-бла.

                Не обьяснили, а заявили. Причём заявили голословное — без ссылок на исследования. Я-то надеялся, что вы вышеупомянутую статью читали, раз берётесь обо всём этом размышлять.

                Я вам не буду говорить о том на что годны эти ссылки. Есть реальный мир. Го вам в руки и вперёд срывать покровы.

                Вы действительно не понимаете что чушь здесь написали? Это же азы всей теории! В случае с GC затраты времени не просто зависят от того, сколько у вас «лишней» памяти,

                Вот типичный пример вранья. Я говорил о времени пауз в ответ на рассуждения о времени пауз. Ни о каких затратах памяти речь не шла. Нигде. И вы этого не покажете.

                И сейчас меня цитируют БЕЗ СЛОВА О ПАМЯТИ, но рассказывают о том, ЧТО Я ГОВОРИЛ О ПАМЯТИ.

                а очень сильно от этого зависят. Как и в случае с обычным распределением памяти, впрочем (локальная память для потока в каком-нибудь tcmalloc'е тоже ведь требует некоторого «запаса»).

                Обычное распределение памяти находится далеко за рамками маллока. Эти все рассуждения ничего не стоят вне академической среды. Как и х5 по памяти.

                Сравнения глупые, некорректные и не реализуемые в реальности. Чисто попускать хелворды.


    1. beduin01
      20.09.2017 22:33
      +6

      >Тем, кто сидит на Java или C# смотрят на Go.
      Интересно почему?)) После C# Go выглядит еще более убого чем Basic.


      1. Akon32
        21.09.2017 10:39
        +5

        Да и после Java тоже не очень.


        1. Caefah
          22.09.2017 09:26
          -5

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


          1. 0xd34df00d
            22.09.2017 20:59
            +2

            Это в С-то строгая типизация?


            1. Caefah
              22.09.2017 22:43

              Бес попутал ) Хотел сказать динамическая типизация, в противовес статической.


  1. halpro
    20.09.2017 17:41
    +2

    И в этих синтетических «попугаях» не учитывают, что вытворяет код и данные приложения под нагрузкой.