2016-12-30 6 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" 

При компиляции с ехом, «Посылает» печатаются, но тогда он висит. Если вы хотите опробовать его, полный код на 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 

и теперь код выполняет, как я планировал.

 Смежные вопросы

  • Нет связанных вопросов^_^