2016-12-30 27 views
5

MailboxProcessor bir ileti aldığında veritabanına bir satır ekleyen bir kod parçam var. Fsi'de çalışırken doğru çalışır, ancak bir exe'ye derlendiğinde kilitlenir. aşağıdaki gibi script:F # program düzgün bir şekilde çalışır, ancak bir exe olarak kilitleniyor

bir exe derlenmiş
#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" 

, yazdırılan "verilmesi yeterlidir", ama sonra asar. Bunu denemek isterseniz, tüm kod github here

+3

Tam olarak neden takıldığından emin değilim, ancak 'ctx'i yanlış kullandığınızı söyleyebilirim. Veri bağlamının “kısa ömürlü” olması gerekiyor - yani, her türlü bağımsız operasyon için yeniden yaratıldı ve hemen imha edildi. Ancak tüm süreç için tek bir bağlam kullanıyorsunuz. –

cevap

5

üzerindedir. Sorun, ana iş parçasının MailboxProcessor posta kutusunun işlenmesinden önce çıkmasıydı. FSI uzun ömürlü ve bu yüzden orada olmuyordu.

[<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 

ve şimdi kod amacı vardı olarak yürütür: Değiştim.