2016-12-30 55 views
5

我有一段代碼在MailboxProcessor收到消息時向數據庫添加一行。它在fsi中運行時工作正常,但編譯爲exe時會掛起。腳本如下:F#程序在fsi中正確運行,但作爲exe掛起

#r "../packages/Newtonsoft.Json/lib/net40/Newtonsoft.Json.dll" 
#r "../packages/SQLProvider/lib/FSharp.Data.SqlProvider.dll" 

open Newtonsoft.Json 
open FSharp.Data.Sql 
open System 

let [<Literal>] ResolutionPath = __SOURCE_DIRECTORY__ + "/../build/" 
let [<Literal>] ConnectionString = "Data Source=" + __SOURCE_DIRECTORY__ + @"/test.db;Version=3" 

// test.db is initialized as follows: 
// 
// BEGIN TRANSACTION; 
// CREATE TABLE "Events" (
//  `id`INTEGER PRIMARY KEY AUTOINCREMENT, 
//  `timestamp` DATETIME NOT NULL 
// ); 
// COMMIT; 

type Sql = SqlDataProvider< 
      ConnectionString = ConnectionString, 
      DatabaseVendor = Common.DatabaseProviderTypes.SQLITE, 
      ResolutionPath = ResolutionPath, 
      IndividualsAmount = 1000, 
      UseOptionTypes = true > 
let ctx = Sql.GetDataContext() 

let agent = MailboxProcessor.Start(fun (inbox:MailboxProcessor<String>) -> 
    let rec loop() = 
     async { 
      let! msg = inbox.Receive() 
      match msg with 
      | _ -> 
       let row = ctx.Main.Events.Create() 
       row.Timestamp <- DateTime.Now 
       printfn "Submitting" 
       ctx.SubmitUpdates() 
       printfn "Submitted" 
      return! loop() 
     } 
    loop() 
) 

agent.Post "Hello" 

當編譯爲exe文件時,會打印「正在提交」,但會掛起。如果你想嘗試一下,完整的代碼是在github here

+3

我不確定它爲什麼掛起,但我可以告訴你,你濫用'ctx'。數據上下文被認爲是「短命的」 - 即爲每個自包含的操作重新創建並立即銷燬。但是你在整個過程中使用單一的上下文。 –

回答

5

看來問題是,主線程退出之前MailboxProcessor可以處理它的郵箱。 FSI壽命很長,所以這不會發生在那裏。我改變:

[<EntryPoint>] 
let main argv = 
    agent.Post "Hello" 
    agent.Post "Hello again" 
    0 

[<EntryPoint>] 
let main argv = 
    agent.Post "Hello" 
    agent.Post "Hello again" 
    let waitLoop = async { 
     while agent.CurrentQueueLength > 0 do 
      printfn "Sleeping" 
      do! Async.Sleep 1000 
     } 
    Async.RunSynchronously waitLoop 
    0 

現在的代碼執行,因爲我本來打算。

相關問題