2016-12-30 49 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 

现在的代码执行,因为我本来打算。

相关问题