openlang

В outliers.log строк больше, чем в счётчике :outliers, 8 futures

Я сворачиваю 20000 симулированных показаний приливов в один atom из 8 futures. Каждое показание выше порога ещё и дописывается в outliers.log. Сводка в порядке: :n всегда 20000, а :outliers одинаковый при каждом запуске, потому что seed фиксированный. Но в логе строк больше, чем в счётчике. В последнем запуске было около 250 строк при счётчике чуть ниже. Некоторые id встречаются дважды. С --workers 1 всё сходится.

(defn- log-line [& parts]
  (spit (:log-file config)
        (str (str/join " " parts) "\n")
        :append true))

(defn fold-reading [st r]
  (let [lvl (:level r)]
    (when (outlier? r)
      (log-line "outlier" (:id r) (format "%.3f" lvl)))
    (cond-> (-> st
                (update :n inc)
                (update :sum + lvl)
                (update :sumsq + (* lvl lvl)))
      (outlier? r) (update :outliers inc))))

(defn record! [r]
  (swap! stats fold-reading r))

Я думал, что spit :append из многих потоков пишет дважды, но тогда и счётчик был бы неверным. Я также проверил чанки partition-all, они не пересекаются, раз :n ровно 20000. Лог я удаляю перед каждым запуском. При следующем запуске с тем же seed количество строк снова другое.

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

Переведено с английскогоПоказать оригинал

Разговор продолжается 1

Следуя доводам
  1. Ссылка на ответ

    Мне кажется, виновник это повторные попытки swap!. Когда 8 futures бьют в один atom, compare-and-set иногда не проходит, и функция запускается снова на новом значении. Коммитится только выигравший результат, поэтому счётчик точный. Но spit срабатывает на каждой попытке, в том числе на отброшенных. Это же объясняет, почему с --workers 1 всё сходится и почему число дублей меняется от запуска к запуску, верно? В atoms reference сказано, что функция может вызываться несколько раз, поэтому она должна быть без побочных эффектов.

    Может, как-то так, с чистой fold-reading:

    (defn record! [r]
      (when (outlier? r)
        (log-line "outlier" (:id r) (format "%.3f" (:level r))))
      (swap! stats fold-reading r))

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

    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. Контекст отменён, но горутины-воркеры живы после первой ошибки (всегда workers + 2)

    Всем привет, Пишу небольшой CLI на Go, shotcheck, который проверяет каждый PNG в папке на точное соответствие размеру, которы…

    Ответы 4Последняя активность go
  2. Пометка фильтра как async не помогла с фризом

    ledgerscan, поиск по 400k записей. сделал run async и вызываю через await из main, думал, что 100 мс heartbeat Timer продолжи…

    Ответы 2Последняя активность dart
  3. await for по ReceivePort никогда не завершается после того, как изоляты закончили

    всем привет, у меня небольшая тулза на Dart, она делает сводку по CSV с температурами, и я запускаю по одному изоляту на файл…

    Ответы 2Последняя активность dart