Reputation: 617
I am learning F# through building an ASP.NET Core app. I need to implement an interface Microsoft.AspNetCore.Identity.IUserStore<'TUser>
; this interface features methods that return Task
like:
member this.CreateAsync (user : User, cancellationToken : CancellationToken) =
async {
let connectionString = configuration.GetConnectionString("SocialScoreApp")
let! rowCountResult = user |> createAsync connectionString
match rowCountResult with
| Ok _ -> return IdentityResult.Success
| Error e ->
let identityError = new IdentityError()
identityError.Description <- e
return IdentityResult.Failed(identityError)
} |> Async.StartAsTask
But, according to the documentation, Async.StartAsTask
"executes a computation on the thread pool". But this is an I/O bound operation so I don't want any new threads involved. Is there any way to achieve that?
Edit: This is the createAsync
code for reference:
let createAsync (connectionString : string) (user:User) =
let sql = "..."
let args = dict [
// ...
]
async {
use connection = new SqlConnection(connectionString)
do! connection.OpenAsync() |> Async.AwaitTask
try
let! rowCount = connection.ExecuteAsync(sql, args) |> Async.AwaitTask
return Ok rowCount
with
| e -> return Error e.Message
}
Upvotes: 2
Views: 162
Reputation: 243041
If you look at how things work, the StartAsTask
(source) operation creates a TaskCompletionSource
, which creates a task that is returned to the caller. This is later used to report the result of the computation. In the meantime, the computation is started using QueueAsync
, which invokes QueueWorkItemWithTrampoline
(source) and this uses standard .NET ThreadPool.QueueUserWorkItem
.
This means that when you run StartAsTask
, the async workflow is added to the thread pool. However, the key thing for IO-bound operations is that you are using let!
in your snippet:
let connectionString = configuration.GetConnectionString("SocialScoreApp")
let! rowCountResult = user |> createAsync connectionString
The work item added to the thread pool will only run GetConnectionString
. It will then call createAsync
, which presumably contains some non-blocking IO operation. As soon as the evaluation gets to this point, the work in the thread pool completes and it schedules a callback to be called when the IO operation completes - the callback is invoked later and adds the rest of the computation to thread pool as a new work item. So, you are not blocking the thread pool while the IO operation is running.
Upvotes: 4