Как определиться с количеством одновременных действий? - PullRequest
0 голосов
/ 28 января 2020

В настоящее время я пишу кодировщик и (очевидно) хочу сделать его быстрым.

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

Мне в голову пришли следующие мысли:

  • Если размер файла составляет всего <1 кБ, бесполезно запускать код во многих программах </li>
  • На количество процедур должно влиять количество доступных ядер / потоков
    • , на которых запущено 16 процедур Процессор 4x4 ГГц не будет проблемой, но что с процессором 4x1 ГГц?
    • трудно определить надежно кроссплатформенный
  • Процессор должен быть занят, но не так занят, чтобы другие программы не отвечали (~ 70-i sh%?)
    • трудно определить заранее из-за тактовой скорости и других параметров

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

Уже сделаны попытки:

  • использование линейной функции для определения на основе размера файла
    • требует различных функций на основе CPU
  • синтаксического анализа спецификаций CPU из lscpu
    • не кроссплатформенных * Для 1038 *
    • требуется другая функция для определения на основе частоты

, которые не были удовлетворительными.

1 Ответ

3 голосов
/ 28 января 2020

Вы упоминаете в комментарии, что

каждая программа читает файл, который должен быть закодирован

Но, конечно, файл - любой file - уже каким-то образом закодирован: как простой текст, возможно, или UTF-8 (поток байтов), возможно, собранный в единицы «строк». Или это может быть поток изображений, такой как файл MPEG, состоящий из некоторого количества кадров. Или это может быть база данных, состоящая из записей. Какой бы ни была форма input , она содержит какую-то базовую единицу c, которую вы могли бы подать в свой (пере) кодировщик.

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

Допустим, файл состоит из независимых строк: затем используйте scanner.Scan читать их и передавать каждую строку в канал, который принимает строки. Выделите N, для некоторых N читатели, которые читают канал, по одной строке за раз:

ch := make(chan string)
for i := 0; i < n; i++ {
    go readAndEncode(ch)
}

// later, or immediately:
for s := bufio.NewScanner(os.Stdin); s.Scan(); {
    ch <- s.Text()
}
close(ch)

Если имеется 100 строк и 4 считывателя, первые четыре ch <- s.Text() операции go быстрые и пятый делает паузу до тех пор, пока один из считывателей не закончит кодирование и не вернется к чтению канала.

Если отдельные строки слишком малы, возможно, вам следует прочитать «порцию» (например, 1 МБ ) вовремя. Если в конце чанка есть частичная строка, сделайте резервную копию или прочитайте больше, пока не получите целую строку. Затем отправьте весь блок данных.

Поскольку каналы копируют данных, вы можете вместо этого sh отправить ссылку на блок. 1 Это будет верно для любого большего блока данных. (Строки имеют тенденцию быть короткими, и издержки на их копирование обычно не очень велики по сравнению с издержками на использование каналов в первую очередь. Если ваши строки имеют тип string, смотрите сноску.)

Если строка или кусок строки здесь не являются правильной единицей работы, выясните, что означает . Думайте о горутинах как о людях (или занятых маленьких сусликах), каждый из которых получает одну работу . Они могут зависеть от кого-то другого - другого человека или суслика - выполнять меньшую работу, какой бы она ни была; и наличие десяти человек, или сусликов, работающих над подзадачами, позволяет руководителю управлять ими. Если вам нужно проделать одну и ту же работу N раз, а N не безгранично, вы можете раскрутить N подпрограмм. Если N является потенциально неограниченным, выделите фиксированное число (возможно, на основе #cpus) и подайте их на работу через канал.


1 As Burak Сердар отмечает, что некоторые копии могут быть удалены автоматически: например, строки в действительности являются срезами только для чтения. Типы срезов состоят из трех частей: указатель (ссылка) на базовые данные, длина и емкость. Копирование фрагмента копирует эти три части, но не базовые данные. То же самое относится и к строкам: строковые заголовки пропускают емкость, поэтому при отправке строки через канал копируются только два слова заголовка. Следовательно, многие из очевидных и простых в кодировании способов разделения данных уже будут довольно эффективными.

...