- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想编写一些运行一系列 F# 脚本 (.fsx) 的代码。问题是我可以拥有数百个脚本,如果我这样做:
let shellExecute program args =
let startInfo = new ProcessStartInfo()
do startInfo.FileName <- program
do startInfo.Arguments <- args
do startInfo.UseShellExecute <- true
do startInfo.WindowStyle <- ProcessWindowStyle.Hidden
//do printfn "%s" startInfo.Arguments
let proc = Process.Start(startInfo)
()
scripts
|> Seq.iter (shellExecute "fsi")
Async
(我想这是要走的路)。
open System.Diagnostics
let p = shellExecute "fsi" @"C:\Users\Stringer\foo.fsx"
async {
let! exit = Async.AwaitEvent p.Exited
do printfn "process has exited"
}
|> Async.StartImmediate
Async.Parallel
并行运行批处理正如托马斯建议的那样。如果我的
cut
有更好的实现,请发表评论功能。
module Seq =
/// Returns a sequence of sequences of N elements from the source sequence.
/// If the length of the source sequence is not a multiple
/// of N, last element of the returned sequence will have a length
/// included between 1 and N-1.
let cut (count : int) (source : seq<´T>) =
let rec aux s length = seq {
if (length < count) then yield s
else
yield Seq.take count s
if (length <> count) then
yield! aux (Seq.skip count s) (length - count)
}
aux source (Seq.length source)
let batchCount = 2
let filesPerBatch =
let q = (scripts.Length / batchCount)
q + if scripts.Length % batchCount = 0 then 0 else 1
let batchs =
scripts
|> Seq.cut filesPerBatch
|> Seq.map Seq.toList
|> Seq.map loop
Async.RunSynchronously (Async.Parallel batchs) |> ignore
f
函数必须在
AddHandler
中调用方法,否则我们将永远失去事件......这是代码:
module Event =
let guard f (e:IEvent<´Del, ´Args>) =
let e = Event.map id e
{ new IEvent<´Args> with
member this.AddHandler(d) = e.AddHandler(d); f() //must call f here!
member this.RemoveHandler(d) = e.RemoveHandler(d); f()
member this.Subscribe(observer) =
let rm = e.Subscribe(observer) in f(); rm }
Exited
进程终止时,事件存储在某处,即使进程尚未以
EnableRaisingEvents
开始设置为真。
guard
中启动进程。函数,所以我们确保代码在任何情况下都可以工作:
let createStartInfo program args =
new ProcessStartInfo
(FileName = program, Arguments = args, UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Normal,
RedirectStandardOutput = true)
let createProcess info =
let p = new Process()
do p.StartInfo <- info
do p.EnableRaisingEvents <- true
p
let rec loop scripts = async {
match scripts with
| [] -> printfn "FINISHED"
| script::scripts ->
let args = sprintf "\"%s\"" script
let p = createStartInfo "notepad" args |> createProcess
let! exit =
p.Exited
|> Event.guard (fun () -> p.Start() |> ignore)
|> Async.AwaitEvent
let output = p.StandardOutput.ReadToEnd()
do printfn "\nPROCESSED: %s, CODE: %d, OUTPUT: %A"script p.ExitCode output
return! loop scripts
}
最佳答案
我做了一些实验,这是处理我帖子下方评论和乔尔回答中讨论的问题的一种方法(我认为目前不起作用,但可以修复)。
我认为 Process
的规范是它可以触发Exited
我们设置 EnableRaisingEvents
之后的事件属性(property)给 true
(即使在我们设置属性之前该过程已经完成,也会触发事件)。为了正确处理这种情况,我们需要在将处理程序附加到 Exited
后启用事件的引发。事件。
这是一个问题,因为如果我们使用 AwaitEvent
它将阻止工作流,直到事件触发。调用 AwaitEvent
后我们无能为力从工作流程中(如果我们在调用 AwaitEvent
之前设置属性,那么我们会进行比赛......)。 Vladimir's approach是正确的,但我认为有一种更简单的方法可以解决这个问题。
我将创建一个函数 Event.guard
接受一个事件并返回一个事件,这允许我们指定一些函数,将在处理程序附加到事件后执行。这意味着如果我们在这个函数内部做一些操作(进而触发事件),事件就会被处理。
要将它用于这里讨论的问题,我们需要将我原来的解决方案更改如下。首先,shellExecute
函数不能设置EnableRaisingEvents
属性(property)(否则,我们可能会失去事件!)。其次,等待代码应该是这样的:
let rec loop scripts = async {
match scripts with
| [] -> printf "FINISHED"
| script::scripts ->
let p = shellExecute fsi script
let! exit =
p.Exited
|> Event.guard (fun () -> p.EnableRaisingEvents <- true)
|> Async.AwaitEvent
let output = p.StandardOutput.ReadToEnd()
return! loop scripts }
Event.guard
的使用功能。粗略地说,在工作流将处理程序附加到
p.Exited
之后事件,提供的 lambda 函数将运行(并将启用事件的引发)。但是,我们已经将处理程序附加到事件,所以如果这会立即导致事件,我们很好!
Event
和
Observable
)如下所示:
module Event =
let guard f (e:IEvent<'Del, 'Args>) =
let e = Event.map id e
{ new IEvent<'Args> with
member x.AddHandler(d) = e.AddHandler(d)
member x.RemoveHandler(d) = e.RemoveHandler(d); f()
member x.Subscribe(observer) =
let rm = e.Subscribe(observer) in f(); rm }
module Observable =
let guard f (e:IObservable<'Args>) =
{ new IObservable<'Args> with
member x.Subscribe(observer) =
let rm = e.Subscribe(observer) in f(); rm }
关于f# - 需要有关异步和 fsi 的帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2649161/
我在桌面的“新文件夹”中有以下文件: // File location: "C:\Users\my_user_name\Desktop\New folder\AddOne.fs" // module
传入通知消息的 Android Studio logcat 显示如下 []message[]。 我复制并粘贴到 .txt 文件,它显示 FSImessagePDI 。 这种字符“FSI”和“PDI”是
我已经使用 Visual Studio Community Edition 安装了 F#,还安装了 Visual F# 4.0 Tools 当我从命令提示符运行 fsi 时抛出异常 我也尝试将 F#
我想编写一些运行一系列 F# 脚本 (.fsx) 的代码。问题是我可以拥有数百个脚本,如果我这样做: let shellExecute program args = let startInfo
例如,我错误地重新定义了ref。它取代了默认的 ref。 是否可以删除我的定义并在不重新启动的情况下恢复到原始定义? 最佳答案 let ref = Microsoft.FSharp.Core.Oper
例如,我错误地重新定义了ref。它取代了默认的 ref。 是否可以在不重启的情况下删除我的定义并恢复到原来的定义? 最佳答案 let ref = Microsoft.FSharp.Core.Opera
我读过 fsi.exe (F# Interactive) 不是严格意义上的真正“解释器”,因为它动态编译 F# 代码并显示其输出。 我的印象是“解释器”这个词适用于“动态”语言(即 JavaScrip
我有以下代码: let p = new System.Diagnostics.Process(); printfn "installing %A" "installing" p.StartInfo.F
如果我将下面的模块编译成一个dll namespace MyNs module SomeModule = do printfn "module loading" let x = 23
我在一台有 40 个内核的机器上有以下奇怪的行为:调用 System.Environment.ProcessorCount在fsi (12.0.30815.0) 和 fsianycpu (12.0.3
如何将 F# Interactive 控制台的输出限制为我自己的输出? 在我当前的设置中,fsi 在运行脚本时会写入大量信息(关于数据结构的类型和内容)。 我试过 quiet mode 没有成功。 谢
有什么方法可以检索 FSI session 中的开放命名空间和模块列表?我正在打印一个 F# 引用的表达式,我希望能够区分应该完全限定打印的模块值和不应该打印的模块值。 最佳答案 我不认为有办法做到这
我无法在F#签名文件中定义文字。 我有一个文件File.fs,如下所示: module Thingo = [] let hello = "world" 我需要为其创建一个签名文件,因此最初尝试
几天以来,我无法使用 FSharp Interactive interpreter(Alt + Enter),它给我这条消息:*未能生成 FSI,请确保它在 PATH 中* 此外,如果我运行脚本,它会
没有任何 SQLite .NET 包在 FSI 中工作,即使在 fs 项目中引用模块时也是如此。我试过 System.Data.SQLite,SQLitePCL.raw , 和 Microsoft.D
我正在 Mac OS X/mono 上使用 fsi 学习 F#,但很难知道退出和退出 shell 的命令。 退出,或者 ^D 不起作用,^C 也不起作用。停止 fsi 的命令是什么? 一般来说,在哪里
使用 FSharp.Charting 探索 F# 我原以为我会从一个简单的“hello world”开始,但它留给我的问题比代码行还多。 #load @"..\packages\FSharp.Char
FSI 能否很好地处理多模块/文件 F# 项目?考虑以下项目: 模块.fs: module Xyz let add x y = x + y 程序.fs: module Program open Xyz
我有一个现有的应用程序,我希望能够在其中拥有自己的 FSI session 。虽然不是标准的 FSI session ,但我希望能够使用来自我的应用程序的数据预先填充 FSI session 。 所以
我使用 fsharpi (fsi) 作为后台编译进程,使用 System.Diagnostics.Process 生成进程。我的 ProcessStartInfo 设置如下所示: let psi =
我是一名优秀的程序员,十分优秀!