- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
已更新:此问题包含一个错误,该错误使基准测试毫无意义。我将尝试一个更好的基准来比较 F# 和 Erlang 的基本并发功能,并在另一个问题中查询结果。
我正在尝试了解 Erlang 和 F# 的性能特征。我发现 Erlang 的并发模型非常有吸引力,但出于互操作性的原因我倾向于使用 F#。虽然开箱即用的 F# 没有提供像 Erlang 的并发原语那样的东西——据我所知,async 和 MailboxProcessor 只涵盖了 Erlang 擅长的一小部分——但我一直在尝试了解 F# 性能的可能性明智的。
在 Joe Armstrong 的《Erlang 编程》一书中,他指出 Erlang 中的进程非常便宜。他使用(大致)以下代码来证明这一事实:
-module(processes).
-export([max/1]).
%% max(N)
%% Create N processes then destroy them
%% See how much time this takes
max(N) ->
statistics(runtime),
statistics(wall_clock),
L = for(1, N, fun() -> spawn(fun() -> wait() end) end),
{_, Time1} = statistics(runtime),
{_, Time2} = statistics(wall_clock),
lists:foreach(fun(Pid) -> Pid ! die end, L),
U1 = Time1 * 1000 / N,
U2 = Time2 * 1000 / N,
io:format("Process spawn time=~p (~p) microseconds~n",
[U1, U2]).
wait() ->
receive
die -> void
end.
for(N, N, F) -> [F()];
for(I, N, F) -> [F()|for(I+1, N, F)].
在我的 Macbook Pro 上,生成和终止 10 万个进程 (processes:max(100000)
) 每个进程大约需要 8 微秒。我可以进一步增加进程数量,但一百万似乎会相当一致地破坏事情。
我对 F# 知之甚少,尝试使用 async 和 MailBoxProcessor 来实现这个示例。我的尝试可能是错误的,如下:
#r "System.dll"
open System.Diagnostics
type waitMsg =
| Die
let wait =
MailboxProcessor.Start(fun inbox ->
let rec loop =
async { let! msg = inbox.Receive()
match msg with
| Die -> return() }
loop)
let max N =
printfn "Started!"
let stopwatch = new Stopwatch()
stopwatch.Start()
let actors = [for i in 1 .. N do yield wait]
for actor in actors do
actor.Post(Die)
stopwatch.Stop()
printfn "Process spawn time=%f microseconds." (stopwatch.Elapsed.TotalMilliseconds * 1000.0 / float(N))
printfn "Done."
在 Mono 上使用 F#,启动和终止 100,000 个参与者/处理器每个进程只需不到 2 微秒,大约比 Erlang 快 4 倍。也许更重要的是,我可以扩展到数百万个进程,而不会出现任何明显的问题。启动 1 或 200 万个进程仍然需要每个进程大约 2 微秒。启动 2000 万个处理器仍然是可行的,但速度会减慢至每个进程约 6 微秒。
我还没有花时间完全理解 F# 如何实现异步和 MailBoxProcessor,但这些结果令人鼓舞。我做错了什么吗?
如果不是,Erlang 是否有某些地方可能优于 F#?有什么原因无法通过库将 Erlang 的并发原语引入 F# 中吗?
编辑:由于布莱恩指出的错误,上述数字是错误的。当我修复它时,我会更新整个问题。
最佳答案
在您的原始代码中,您只启动了一个 MailboxProcessor。将 wait()
设为一个函数,并在每次 yield
时调用它。此外,您也不会等待它们启动或接收消息,我认为这会使计时信息无效;请参阅下面的代码。
也就是说,我取得了一些成功;在我的盒子上,我可以执行 100,000 次,每次大约需要 25 秒。经历了太多之后,我想你可能会开始与分配器/GC 进行尽可能多的斗争,但我也能够完成一百万次(每次大约 27us,但此时使用了大约 1.5G 的内存)
基本上每个“挂起的异步”(这是邮箱在像这样的线路上等待时的状态)
let! msg = inbox.Receive()
) 在被阻止时仅占用一定数量的字节。这就是为什么你可以拥有比线程更多的异步;一个线程通常需要一兆字节或更多的内存。
好的,这是我正在使用的代码。您可以使用像 10 这样的小数字,并 --define DEBUG 来确保程序语义是所需的(printf 输出可能是交错的,但您会明白的)。
open System.Diagnostics
let MAX = 100000
type waitMsg =
| Die
let mutable countDown = MAX
let mre = new System.Threading.ManualResetEvent(false)
let wait(i) =
MailboxProcessor.Start(fun inbox ->
let rec loop =
async {
#if DEBUG
printfn "I am mbox #%d" i
#endif
if System.Threading.Interlocked.Decrement(&countDown) = 0 then
mre.Set() |> ignore
let! msg = inbox.Receive()
match msg with
| Die ->
#if DEBUG
printfn "mbox #%d died" i
#endif
if System.Threading.Interlocked.Decrement(&countDown) = 0 then
mre.Set() |> ignore
return() }
loop)
let max N =
printfn "Started!"
let stopwatch = new Stopwatch()
stopwatch.Start()
let actors = [for i in 1 .. N do yield wait(i)]
mre.WaitOne() |> ignore // ensure they have all spun up
mre.Reset() |> ignore
countDown <- MAX
for actor in actors do
actor.Post(Die)
mre.WaitOne() |> ignore // ensure they have all got the message
stopwatch.Stop()
printfn "Process spawn time=%f microseconds." (stopwatch.Elapsed.TotalMilliseconds * 1000.0 / float(N))
printfn "Done."
max MAX
综上所述,我不了解 Erlang,也没有深入思考是否有办法再精简 F#(尽管这很惯用)。
关于concurrency - F# 在生成和终止进程方面真的比 Erlang 更快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2214954/
如果我终止应用程序,我在尝试保持我的功能运行时卡住了。 是否可以在应用程序未运行时保持核心位置(地理围栏/地理定位)和核心蓝牙运行?如果可能如何解决我的问题?我已经检查了背景模式,并实现了核心定位方法
该程序要求用户输入一个数字,然后从列表中返回详细信息。我该怎么做? do { Scanner in = new Scanner(System.in);
我正在开发一个内部分发的 iOS 应用程序(即,没有应用程序商店),我希望能够以恒定的 10 分钟间隔报告设备的位置。 无论如何,我在我的 plist 中包含了 location 作为字段 UIBac
我的 mongodb 服务器突然收到信号 15(终止)。我不知道为什么 mongodb 崩溃了。以下是日志消息。 Mon Jun 27 07:33:31.701 [signalProcessingTh
我按顺序运行了一堆malloc,并且每次都检查以确保它是成功的。像这样: typedef struct { int *aray; char *string; } mystruct; m
这个问题已经有答案了: How to stop a running pthread thread? (4 个回答) 已关闭 8 年前。 可以使用 pthread_join() 停止线程。但让我们想象一
#include #include #include struct node{ char data; int p; struct node *ptr; }; struct node *st
这个问题已经有答案了: Why should I use a semicolon after every function in javascript? (9 个回答) 已关闭 8 年前。 好吧,我问
我有一个启动多个工作线程的函数。每个工作线程都由一个对象封装,该对象的析构函数将尝试加入线程,即调用if (thrd_.joinable()) thrd_.join();。但是,每个 worker 必
我正在实现一个应用程序,当用户摇动手机时,该应用程序会监听并采取行动。 所以我实现了以下服务: public class ShakeMonitorService extends Service {
我在使用 Xcode 时遇到问题,其中弹出错误“Source Kit Service Terminated”,并且所有语法突出显示和代码完成在 Swift 中都消失了。我怎样才能解决这个问题? 这是一
我想为我的控制台应用程序安全退出,该应用程序将使用单声道在 linux 上运行,但我找不到解决方案来检测信号是否发送到它或用户是否按下了 ctrl+c。 在 Windows 上有内核函数 SetCon
关键: pthread_cancel函数发送终止信号pthread_setcancelstate函数设置终止方式pthread_testcancel函数取消线程(另一功能是:设置取消点) 1 线程取消
下面的程序在不同的选项级别下有不同的行为。当我用 -O3 编译它时,它永远不会终止。当我用 -O0 编译它时,它总是很快就会终止。 #include #include void *f(void *
我有 3 个节点的 K8S 集群,我创建了 3 个副本 pod,应用程序 app1 在所有 pod 上运行,我通过运行 service yaml 文件建立了服务,我可以看到通过运行 kubectl g
我打算使用 nginx 来代理 websocket。在执行 nginx reload/HUP 时,我知道 nginx 等待旧的工作进程停止处理所有请求。然而,在 websocket 连接中,这可能不会
在 Ubuntu 9.10 上使用 PVM 3.4.5-12(使用 apt-get 时的 PVM 包) 添加主机后程序终止。 laptop> pvm pvm> add bowtie-slave add
我编写了一个应用程序来从 iPhone 录制视频。它工作正常,但有一个大问题。当 AVCaptureSession 开始运行并且用户尝试从其库(iPod)播放音频时。此操作将使 AVCaptureSe
我将如何使用NSRunningApplication?我有与启动应用程序相反的东西: [[NSWorkspace sharedWorkspace] launchApplication:appName]
我正在使用 NSTask 执行一系列长时间运行的命令,如下所示: commandToRun = @"command 1;command2"; NSArray *arguments = [NSArray
我是一名优秀的程序员,十分优秀!