Selaa lähdekoodia

utility: feat: threads

gretmn102 3 vuotta sitten
vanhempi
säilyke
10a3948ec0
1 muutettua tiedostoa jossa 51 lisäystä ja 14 poistoa
  1. 51 14
      Utility/Program.fs

+ 51 - 14
Utility/Program.fs

@@ -10,11 +10,23 @@ let qspSourceExt = ".qsps"
 let changeExtensionToQsp (path:FilePath) =
     System.IO.Path.ChangeExtension(path, qspSourceExt)
 
+module ThreadSafePrint =
+    let mail = MailboxProcessor.Start (fun agent ->
+        let rec loop () =
+            async {
+                let! msg = agent.Receive()
+                printfn "%s" msg
+                return! loop ()
+            }
+        loop ()
+    )
+    let printfn fmt = Printf.ksprintf mail.Post fmt
+
 let decodeGame config (src:FilePath) (dst:FilePath) =
     if System.IO.File.Exists config.Path then
         let args = sprintf "\"%s\" \"%s\" D %s" src dst config.Args
         let startProcString path args =
-            printfn "decoding: `%s %s`" path args
+            ThreadSafePrint.printfn "decoding: `%s %s`" path args
             let drivenOutput = new System.Text.StringBuilder()
             Proc.startProc (fun e ->
                 drivenOutput.AppendLine(e) |> ignore
@@ -39,7 +51,26 @@ let doFile txt2qspConfig updateSourceIfExists src =
     else
         decodeGame txt2qspConfig src dst
 
-let doDir txt2qspConfig updateSourceIfExists dir =
+let threadsExec threads fn xs =    
+    if threads > 1 then
+        xs
+        |> Seq.chunkBySize threads
+        |> Seq.collect (fun paths ->
+            paths
+            |> Array.map (fun x ->
+                async {
+                    return fn x
+                })
+            |> Async.Parallel
+            |> Async.RunSynchronously
+            // // or:
+            // paths
+            // |> Array.Parallel.map fn
+        )
+    else
+        xs |> Seq.map fn
+
+let doDir txt2qspConfig updateSourceIfExists threads dir =
     // TODO:
     // let xs =
     //     System.IO.Directory.EnumerateFiles(dir, "*.*", System.IO.SearchOption.AllDirectories)
@@ -53,17 +84,18 @@ let doDir txt2qspConfig updateSourceIfExists dir =
     //     )
 
     // if use the "*.qsp" mask, it will capture the ".qsps" files as well
-    System.IO.Directory.EnumerateFiles(dir, "*.*", System.IO.SearchOption.AllDirectories)
-    |> Seq.filter (System.IO.Path.GetExtension >> ((=) ".qsp"))
-    |> Seq.map (fun src ->
-        doFile txt2qspConfig updateSourceIfExists src
-    )
+    let xs =
+        System.IO.Directory.EnumerateFiles(dir, "*.*", System.IO.SearchOption.AllDirectories)
+        |> Seq.filter (System.IO.Path.GetExtension >> ((=) ".qsp"))
+    xs
+    |> threadsExec threads (doFile txt2qspConfig updateSourceIfExists)
 
 type CliArguments =
     | Working_Directory of path:FilePath
     | Txt2qsp of path:FilePath * args:string
     | Source_Path of path:FilePath
     | UpdateSourceIfExists
+    | Threads of int
     interface IArgParserTemplate with
         member s.Usage =
             match s with
@@ -71,7 +103,7 @@ type CliArguments =
             | Txt2qsp _ -> "specify a txt2gam (path : args)."
             | Source_Path _ -> "path to encoded game (.qps) or decoded source game (.qsps)."
             | UpdateSourceIfExists -> "decodes the source, even if it exists."
-
+            | Threads _ -> "number of threads per file, by default is 1."
 module Parser =
     open FParsec
     open Qsp.Parser.Generic
@@ -184,7 +216,12 @@ let main argv =
                 |> Some
             | _ -> None
         ) |> Either.ofOption "not defined --txt2qsp"
-
+    let threads =
+        results
+        |> List.tryPick (function
+            | Threads i -> Some i
+            | _ -> None
+        ) |> Option.defaultValue 1
     let folder =
         results
         |> List.tryPick (function
@@ -196,7 +233,7 @@ let main argv =
     let folderExec folder =
         txt2qspConfig
         |> Either.map (fun config ->
-            doDir config updateSourceIfExists folder
+            doDir config updateSourceIfExists threads folder
         )
         |> Either.seqEitherPseudo
 
@@ -254,9 +291,9 @@ let main argv =
         | Right folder ->
             let pattern = getPattern ()
             folderExec folder
-            |> Seq.map (
-                Either.bind (fun path ->
-                    printfn "parse: %s" path
+            |> threadsExec threads
+                (Either.bind (fun path ->
+                    ThreadSafePrint.printfn "parse: %s" path
                     match Qsp.Parser.Main.startOnFile enc path with
                     | FParsec.CharParsers.Success(locs, st, _) ->
                         locs
@@ -287,6 +324,6 @@ let main argv =
 
     all ()
     |> Seq.map (sprintf "%A")
-    |> uncurry System.IO.File.WriteAllLines "output.txt"
+    |> uncurry System.IO.File.WriteAllLines "output.log"
 
     0