Раскрыть недетерминированность в результате планировщика потока ОС

10

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

Цель здесь противоположна. Создайте программу, которая печатает целые числа в интервале [0,99], но в порядке, который будет варьироваться от запуска к запуску из-за планировщика потока ОС.

Вы должны достичь «достаточного недетерминизма», определяемого как:

В 10 последовательных наборах из 10 испытаний ваша программа должна производить не менее 9 уникальных перестановок в каждом испытании. У вас может быть разумное количество неудачных наборов испытаний по обе стороны от 10 последовательных, которые будут успешными.

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

Таким образом, иногда замена 98 и 99 не приведет к сокращению.

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

мелочи

  • Запишите свой вывод на стандартный вывод, по одной записи в строке
  • Если вы изменяете формат с помощью чередования двух потоков записи символов в стандартный вывод (даже иногда), что приводит к таким вещам, как трехзначные числа или пустые строки, ваш результат будет недействительным
  • Единственное исключение из приведенного выше правила состоит в том, что вы можете выдать одну пустую строку после печати последнего требуемого номера (пожалуйста)
  • Если вы когда-нибудь пропустите или продублируете обязательные значения, ваш результат будет недействительным
  • Ваша программа не должна быть недетерминированной на одноядерном процессоре (хотя, если вам так хочется)
  • Ваша программа может использовать зеленые потоки / волокна, которые на самом деле не управляются ядром ОС, если она все еще отвечает другим требованиям задачи, а система потоков является частью вашего языка или стандартной библиотеки для вашего языка.
  • Время выполнения вашей программы должно быть надежно менее 5 секунд на современном процессоре
  • Вы не можете указать изменения в среде, которые происходят вне вашей программы, такие как ожидание или изменение настроек; ваша программа должна проходить независимо от того, запускается ли она 100 раз подряд или с интервалом в час между каждым запуском или 100 раз параллельно (это, вероятно, поможет на самом деле ...)
  • Вы можете использовать сопроцессор, такой как GPU или Xeon Phi, и собственный механизм внутреннего планирования для задач. Правила применяются к этому так же, как к зеленым нитям.
  • Не стесняйтесь спровоцировать планировщик всевозможными снами, выходами и другими хитростями, если вы подчиняетесь правилам, указанным в этом посте.

Запрещенные операции

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

  • Прямой или косвенный доступ к любому виду возможностей PRNG или аппаратного RNG (если только он не является неотъемлемой частью планировщика).
  • Чтение в любом виде ввода (системное время, файловая система, сеть и т. Д.)
  • Чтение идентификаторов потоков или идентификаторов процессов
  • Настройка планировщика ОС; вы должны использовать стандартный планировщик ОС из основной ОС
  • Настройка вашего зеленого планировщика нитей / волокон также запрещена. Это означает, что если вы пишете язык для этой задачи, вы должны использовать потоки ОС.

Подтверждение ответа

Желательно, чтобы ответ работал во всех распространенных операционных системах и современных процессорах, а почетность награды была пропорциональна широте поддержки. Тем не менее, это не требование задачи. Как минимум ответ должен поддерживать один современный процессор SMP и современную ОС. Я опробую опережающие ответы в зависимости от доступности моего оборудования.

  • Если ваша запись не произведет требуемый вывод на i7 5960x под управлением Windows 10 v1607 x64, укажите требуемую среду
  • Если это что-то, что я могу легко воспроизвести с VMWare Workstation, предоставьте точные спецификации ОС и ВМ
  • Если он не может быть воспроизведен ни в одном из этих условий, запишите одновременный снимок экрана теста, как описано в разделе заголовка, и ручную видеозапись вашего экрана с помощью взаимодействия мыши и клавиатуры (или какой-либо другой схемы управления вашими нестандартными вычислениями). устройство использует) четко видны и публикуют оба видео вместе с вашим ответом и включают объяснение того, почему оно работает
  • В качестве альтернативы, получите уважаемого давнего пользователя (который не является вами) с соответствующим оборудованием, чтобы воспроизвести результат и поручиться за вас
  • Если ваша запись написана на экзотическом языке программирования, который типичный разработчик не настроит на компиляцию / jit / интерпретацию, предоставьте инструкции по установке
  • Если ваша запись зависит от конкретной версии интерпретатора JVM / Python / другой, укажите, какая
  • Если вам потребуется более 10 минут последовательных прогонов, чтобы получить 10 успешных последовательных наборов испытаний в моем тестировании, вы провалите (поэтому не допускайте, чтобы условие успеха было странным, особенно если вы находитесь на верхнем уровне). время выполнения)
Techrocket9
источник
4
-1 за "Если мне скучно ....". Я бы сказал, точно укажите, сколько времени это может занять.
Rɪᴋᴇʀ
@EasterlyIrk Он также говорит: «Надежно, менее чем за пять секунд на современном процессоре»
Павел
@ Павел, это не то, что я имею в виду. 10 успешных испытаний не связаны с 5 секундами.
Rɪᴋᴇʀ
@EasterlyIrk Достаточно справедливо, сейчас 10 минут.
Techrocket9
@ Techrocket9 круто, downvote отменен.
Rɪᴋᴇʀ

Ответы:

4

Perl 6 , 27 байт

await map {start .say},^100

Объяснение:

      map {          },^100  # Iterate over the range 0..99, and for each of number:
           start             # Send the following task to a thread pool of OS threads:
                 .say        # Print the number, followed by a newline.
await                        # Wait until all tasks have completed.

Я надеюсь, что это удовлетворяет задачу. (Если нет, пожалуйста, дайте мне знать).

Тестирование:

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

#!/usr/bin/bash
for i in {1..10}; do
    set=""
    for j in {1..10}; do
        set="${set}$(perl6 nondet.p6 | tr '\n' ',')\n"
    done
    permutations="$(echo -e "$set" | head -n -1 | sort | uniq | wc -l)"
    echo -n "$permutations "
done

Для меня это выводы:

10 10 10 10 10 10 10 10 10 10 

Инструкция по настройке:

Я провел тест с современной версией Rakudo Perl 6 на 64-битной Linux, хотя я думаю, что она будет работать на других платформах.

На странице загрузки Rakudo есть инструкции по настройке. Я скомпилировал мой из git так:

git clone git@github.com:rakudo/rakudo.git
cd rakudo
perl Configure.pl --gen-moar --make-install
export PATH="$(pwd)/install/bin/:$PATH"

Попробуйте онлайн:

Или просто протестируйте его в Интернете, используя ссылку « Попробуй онлайн», предоставленную @ b2gills. Я проверил несколько прогонов и каждый раз получал новый заказ, но у меня не хватило терпения 100 раз выполнить его через этот онлайн-интерфейс.

SMLS
источник
Проверено на Windows 10 x64 на i7 5960x с Rakudo Perl версия 2016.11
Techrocket9
4

Баш, 32 28 байт

for i in {0..99};{ echo $i&}

Я пробежал 100 раз и получил 100 разных результатов.

Редактировать: 4 байта сохранены благодаря @DigitalTrauma.

Нил
источник
Ты подтолкнул меня на это. На самом деле мой немного короче for i in {0..99};{ echo $i&}, но вы отправили первым - вы можете взять его :)
Digital Trauma
Вот способ, которым вы можете проверить это в TIO. Это делает 10 запусков скрипта, собирая выходные данные каждого запуска, а md5 - вывод каждого запуска. Мы видим, что MD5 каждый раз разные. MD5 сортируются, чтобы выявить потенциальные дубликаты.
Цифровая травма
@DigitalTrauma без документов, но приятно!
Нил
1
Да, есть подсказка для этого.
Цифровая травма
Интересно, что этого не удается достичь «достаточного недетерминизма» при запуске в официальном bash-on-windows от Microsoft на E5-2699 v4, но он работает в виртуальной машине RHEL Workstation с 4 ядрами на одной машине, поэтому он проходит.
Techrocket9
2

PowerShell , 54 46 44 39 байт

workflow p{foreach -p($i in 0..99){$i}}

Рабочие процессы PowerShell не поддерживаются в TIO, поэтому вы не можете попробовать их там. Должен отлично работать на вашем компьютере с Windows 10, хотя :)

Определяет функцию, pкоторая будет выводить список чисел при вызове.

тайминг

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

тестирование

Вот полный код, чтобы проверить это:

workflow p{foreach -p($i in 0..99){$i}}
#workflow p{foreach($i in 0..99){$i}}
# uncomment above to prove testing methodology does detect duplicates

1..10 | % {
    $set = $_
    Write-Host "Set $set of 10"
    1..10 | % -b {
        $runs = @()
    } -p {
        $run = $_
        Write-Host "-- Run $run of 10 in set $set"
        $runs += "$(p)"
    } -e {
        Write-Host "-- There were $(10-($runs|Get-Unique).Count) duplicate runs in set $set"
    }
}

Вывод на мою машину:

Set 1 of 10
-- Run 1 of 10 in set 1
-- Run 2 of 10 in set 1
-- Run 3 of 10 in set 1
-- Run 4 of 10 in set 1
-- Run 5 of 10 in set 1
-- Run 6 of 10 in set 1
-- Run 7 of 10 in set 1
-- Run 8 of 10 in set 1
-- Run 9 of 10 in set 1
-- Run 10 of 10 in set 1
-- There were 0 duplicate runs in set 1
Set 2 of 10
-- Run 1 of 10 in set 2
-- Run 2 of 10 in set 2
-- Run 3 of 10 in set 2
-- Run 4 of 10 in set 2
-- Run 5 of 10 in set 2
-- Run 6 of 10 in set 2
-- Run 7 of 10 in set 2
-- Run 8 of 10 in set 2
-- Run 9 of 10 in set 2
-- Run 10 of 10 in set 2
-- There were 0 duplicate runs in set 2
Set 3 of 10
-- Run 1 of 10 in set 3
-- Run 2 of 10 in set 3
-- Run 3 of 10 in set 3
-- Run 4 of 10 in set 3
-- Run 5 of 10 in set 3
-- Run 6 of 10 in set 3
-- Run 7 of 10 in set 3
-- Run 8 of 10 in set 3
-- Run 9 of 10 in set 3
-- Run 10 of 10 in set 3
-- There were 0 duplicate runs in set 3
Set 4 of 10
-- Run 1 of 10 in set 4
-- Run 2 of 10 in set 4
-- Run 3 of 10 in set 4
-- Run 4 of 10 in set 4
-- Run 5 of 10 in set 4
-- Run 6 of 10 in set 4
-- Run 7 of 10 in set 4
-- Run 8 of 10 in set 4
-- Run 9 of 10 in set 4
-- Run 10 of 10 in set 4
-- There were 0 duplicate runs in set 4
Set 5 of 10
-- Run 1 of 10 in set 5
-- Run 2 of 10 in set 5
-- Run 3 of 10 in set 5
-- Run 4 of 10 in set 5
-- Run 5 of 10 in set 5
-- Run 6 of 10 in set 5
-- Run 7 of 10 in set 5
-- Run 8 of 10 in set 5
-- Run 9 of 10 in set 5
-- Run 10 of 10 in set 5
-- There were 0 duplicate runs in set 5
Set 6 of 10
-- Run 1 of 10 in set 6
-- Run 2 of 10 in set 6
-- Run 3 of 10 in set 6
-- Run 4 of 10 in set 6
-- Run 5 of 10 in set 6
-- Run 6 of 10 in set 6
-- Run 7 of 10 in set 6
-- Run 8 of 10 in set 6
-- Run 9 of 10 in set 6
-- Run 10 of 10 in set 6
-- There were 0 duplicate runs in set 6
Set 7 of 10
-- Run 1 of 10 in set 7
-- Run 2 of 10 in set 7
-- Run 3 of 10 in set 7
-- Run 4 of 10 in set 7
-- Run 5 of 10 in set 7
-- Run 6 of 10 in set 7
-- Run 7 of 10 in set 7
-- Run 8 of 10 in set 7
-- Run 9 of 10 in set 7
-- Run 10 of 10 in set 7
-- There were 0 duplicate runs in set 7
Set 8 of 10
-- Run 1 of 10 in set 8
-- Run 2 of 10 in set 8
-- Run 3 of 10 in set 8
-- Run 4 of 10 in set 8
-- Run 5 of 10 in set 8
-- Run 6 of 10 in set 8
-- Run 7 of 10 in set 8
-- Run 8 of 10 in set 8
-- Run 9 of 10 in set 8
-- Run 10 of 10 in set 8
-- There were 0 duplicate runs in set 8
Set 9 of 10
-- Run 1 of 10 in set 9
-- Run 2 of 10 in set 9
-- Run 3 of 10 in set 9
-- Run 4 of 10 in set 9
-- Run 5 of 10 in set 9
-- Run 6 of 10 in set 9
-- Run 7 of 10 in set 9
-- Run 8 of 10 in set 9
-- Run 9 of 10 in set 9
-- Run 10 of 10 in set 9
-- There were 0 duplicate runs in set 9
Set 10 of 10
-- Run 1 of 10 in set 10
-- Run 2 of 10 in set 10
-- Run 3 of 10 in set 10
-- Run 4 of 10 in set 10
-- Run 5 of 10 in set 10
-- Run 6 of 10 in set 10
-- Run 7 of 10 in set 10
-- Run 8 of 10 in set 10
-- Run 9 of 10 in set 10
-- Run 10 of 10 in set 10
-- There were 0 duplicate runs in set 10
briantist
источник
Интересно, что на моем компьютере E5-2699 v4 это занимает 51 секунду, но на ноутбуке i5-5200U - всего 0,7 секунды. Он достигает требуемой степени недетерминированности на ноутбуке, в то время как его максимальная скорость составляет менее 5 секунд, поэтому он проходит. По-видимому, планировщик PowerShell плохо работает со многими ядрами и короткими задачами.
Techrocket9
И это займет 58 секунд на i7 5960x
Techrocket9
Хм ... 74 секунды на ноутбуке i5-6300U. Возможно, это проблема с Windows 10 или PowerShell 5.1, так как i5-5200U - единственная машина среди протестированных, не работающих под Win10 (работает под управлением 8.1).
Techrocket9
@ Techrocket9 странно, я тестировал на Win10, PS 5.1. В ИСЕ хотя.
бриантист
2

GCC на Linux, 47 байт

main(i){for(i=99;fork()?i--:!printf("%d\n",i););}

Это дало мне разные результаты в значительной степени каждый раз, будучи скомпилированным gcc(без флагов) версии 4.9.2. В частности, я работал на 64-битном Debian 8.6 (версия ядра 3.16.31).

объяснение

Если fork()возвращается ноль (дочерний процесс), значение iпечатается, и условие цикла ложно, потому printfчто вернет значение больше нуля. В родительском процессе условие цикла просто i--.

Дэн Гетц
источник
То же, что и ответ Bash. Детерминирован в Windows, но проходит в Linux (в данном случае в Debian).
Techrocket9