公开由OS线程调度程序引起的不确定性


10

众所周知,现代操作系统具有线程调度程序,可以根据您的代码不了解的内部逻辑来选择不同的顺序来调度线程。通常,您设计多线程代码以确保强加给您的这种不确定性不会对您的输出产生有意义的影响。

这里的目标是相反的。产生一个程序,该程序以[0,99]为间隔打印整数,但由于OS线程调度程序的原因,该顺序因运行而异。

您必须实现“足够的不确定性”,定义为:

在10个试验的10个顺序集合中,您的程序必须在每个试验中至少产生9个唯一排列。在连续成功的10个测试中,您可能会有相当数量的失败尝试。

或者,换句话说,您需要运行100次程序,其中每10次运行的程序块最多具有两次输出相同结果的运行。

因此,偶尔将98和99交换不会减少费用。

这是一个,因此使用最少字节的答案将获胜。

细节

  • 将输出写入标准输出,每行一个条目
  • 如果您通过让两个线程将字符写入stdout(甚至偶尔)交织字符来破坏格式(导致偶发三位数或空行的情况),则结果无效
  • 上述规则的唯一例外是,您可以在打印最后一个所需的数字后发出一个空行(不客气)
  • 如果错过或重复任何必需的值,则结果无效
  • 您的程序不必在单个核心处理器上具有确定性(尽管是赞誉的)
  • 如果您的程序仍然可以满足挑战的其他要求,并且线程系统是您的语言或您的语言的标准库的一部分,则您的程序可能使用实际上不受OS内核管理的绿色线程/纤维。
  • 在现代处理器上,程序的运行时间必须可靠地在5秒以内
  • 您不必指定在程序之外发生的环境更改,例如等待或设置更改。无论程序是连续运行100次还是每次运行之间有一个小时还是并行运行100次,您的程序都应该通过(这实际上可能会有所帮助...)
  • 您可以使用诸如GPU或Xeon Phi之类的协处理器及其自身的内部调度机制来执行任务。规则适用于此的方式与适用于绿色线程的方式相同。
  • 只要遵守本文中指定的规则,就可以通过各种睡眠,良率和其他技巧来激发调度程序

禁止操作

允许使用不确定性的唯一来源是调度程序调度线程运行的时间。以下列表并非详尽无遗,仅是为了提供一些示例,这些示例是您接受其他不确定性来源时被禁止执行的操作。

  • 直接或间接访问任何种类的PRNG或硬件RNG功能(除非它是调度程序的固有部分)。
  • 读取任何类型的输入(系统时间,文件系统,网络等)
  • 读取线程ID或进程ID
  • 自定义操作系统调度程序;您必须使用主流操作系统中的标准操作系统调度程序
  • 也禁止自定义绿色线程/光纤调度程序。这意味着,如果您为此挑战编写语言,则必须使用OS线程。

答案验证

最好在所有常见的OS和现代处理器上都可以找到答案,并根据支持的广度来授予荣誉。但是,这不是挑战的要求。答案至少必须支持一个现代的SMP处理器和现代的操作系统。我将在硬件可用性方面测试主要答案。

  • 如果您的输入将不会在运行Windows 10 v1607 x64的i7 5960x上产生所需的输出,请指定所需的环境
  • 如果可以通过VMWare Workstation轻松复制,请提供确切的OS和VM规格
  • 如果在上述两种情况下均无法生成,请同时记录测试内容的屏幕截图,如标题部分所述,并通过鼠标和键盘的交互作用(或任何非标准计算的控制方案)对屏幕进行手持视频录制设备使用)清晰可见,并将两个视频以及您的答案一起发布,并说明其工作原理
  • 或者,使用匹配的硬件找一个久负盛名的长期用户(不是您)来重现结果并为您提供担保
  • 如果您的输入使用的是外来编程语言,而典型的开发人员将不会被设置为编译/编辑/解释,请提供安装说明
  • 如果您输入的内容取决于特定版本的JVM / Python解释器/其他版本,请指定
  • 如果要在我的测试中连续进行10次以上的连续试验需要花费超过10分钟的时间,那么您将失败(因此,不要让成功的情况异常发生,尤其是当您处于较高水平时)运行时绑定)

4
-1表示“如果我感到无聊...”。我想确切说明需要多长时间。
Rɪᴋᴇʀ

@EasterlyIrk它还说“在现代CPU上可靠地在5秒内”
Pavel

@Pavel不是我要指的是。10次​​成功的试验与5秒无关。
Rɪᴋᴇʀ

@EasterlyIrk足够公平了,现在是10分钟。
Techrocket17年

@ Techrocket9很酷,不赞成投票。
Rɪᴋᴇʀ

Answers:


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.

我希望这可以满足任务。(如果没有,请告诉我)。

测试:

我用来测试足够的不确定性的shell脚本:

#!/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 

设置说明:

我在64位Linux上使用最新的Rakudo Perl 6进行了测试,尽管我认为它可以在其他平台上运行。

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次。



在带有Rakudo Perl版本2016.11的i7 5960x的Windows 10 x64上进行了验证
Techrocket9

4

bash,32个 28字节

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

我跑了100次,得到了100个不同的结果。

编辑:由于@DigitalTrauma,节省了4个字节。


你击败了我。实际上我的要短一点for i in {0..99};{ echo $i&},但是您先发布了-您可以接受它:)
Digital Trauma

您可以通过以下方式在TIO中对其进行测试。这将执行10次脚本运行,捕获每次运行的输出,它们对每次运行的输出进行md5处理。我们可以看到md5每次都不同。md5被排序以使潜在的重复变得明显。
Digital Trauma

@DigitalTrauma没有证件,但很好!
尼尔

1
是的-有一个提示
Digital Trauma

有趣的是,当在E5-2699 v4上的Microsoft官方Windows上bash-on窗口中运行时,这无法实现“足够的不确定性”,但是它可以在同一台计算机上具有4个内核的RHEL Workstation VM中运行,因此可以通过。
Techrocket17年

2

PowerShell54 46 44 39字节

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

TIO不支持PowerShell工作流,因此您不能在那里尝试。应该可以在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

有趣的是,这在我的E5-2699 v4机器上每次运行需要51秒,而在我的i5-5200U笔记本电脑上仅需要0.7秒。在5秒以下的最大时间内达到笔记本电脑所需的不确定性程度,因此它可以通过。显然,PowerShell的调度程序不能很好地用于许多内核和简短任务。
Techrocket17年

在i7 5960x上花费58秒
Techrocket9

嗯... i5-6300U笔记本电脑上74秒。也许这是Windows 10或PowerShell 5.1的问题,因为i5-5200U是经过测试的唯一不运行Win10(运行8.1)的计算机。
Techrocket9

@ Techrocket9很奇怪,我正在Win10,PS 5.1上进行测试。在ISE中。
briantist

2

Linux上的GCC,47字节

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

每次使用gcc4.9.2版(无标志)编译时,几乎每次都得到不同的结果。具体来说,我使用的是64位Debian 8.6(内核版本3.16.31)。

说明

如果fork()返回零(子进程),i则打印的值,并且循环条件为false,因为printf它将返回大于零的值。在父进程中,循环条件为i--


与bash答案相同。在Windows上具有确定性,但在Linux(在本例中为Debian)上传递。
Techrocket17年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.