如何从 C# 调用和处理异步 F# 工作流

发布于 2024-11-01 14:39:56 字数 2049 浏览 1 评论 0原文

我读过一些 F# 教程,并且注意到与 C# 相比,在 F# 中执行异步和并行编程是多么容易。因此,我试图编写一个 F# 库,它将从 C# 调用,并采用 C# 函数(委托)作为参数并异步运行它。

到目前为止,我已经成功地传递了该函数(我什至可以取消),但我错过的是如何实现回调回 C#,该回调将在异步操作完成后立即执行。 (例如函数AsynchronousTaskCompleted?)。另外,我想知道是否可以从 AsynchronousTask 函数将(例如进度%)发回 F#。

有人可以帮我吗?

这是我到目前为止编写的代码(我不熟悉 F#,因此以下代码可能是错误的或实现得不好)。

//C# Code Implementation (How I make the calls/handling)
        //Action definition is: public delegate void Action();
        Action action = new Action(AsynchronousTask);
        Action cancelAction = new Action(AsynchronousTaskCancelled);
        myAsyncUtility.StartTask2(action, cancelAction);
        Debug.WriteLine("0. The task is in progress and current thread is not blocked");
        ......
        private void AsynchronousTask()
        {
            //Perform a time-consuming task
            Debug.WriteLine("1. Asynchronous task has started.");
            System.Threading.Thread.Sleep(7000);
            //Post progress back to F# progress window?
            System.Threading.Thread.Sleep(2000);
        }        
        private void AsynchronousTaskCompleted(IAsyncResult asyncResult)
        {           
            Debug.WriteLine("2. The Asynchronous task has been completed - Event Raised");
        }
        private void AsynchronousTaskCancelled()
        {
            Debug.WriteLine("3. The Asynchronous task has been cancelled - Event Raised");
        }

//F# Code Implementation
  member x.StartTask2(action:Action, cancelAction:Action) = 
        async {
            do! Async.FromBeginEnd(action.BeginInvoke, action.EndInvoke, cancelAction.Invoke)
            }|> Async.StartImmediate
        do printfn "This code should run before the asynchronous operation is completed"    
        let progressWindow = new TaskProgressWindow()
        progressWindow.Run() //This class(type in F#) shows a dialog with a cancel button
        //When the cancel button is pressed I call Async.CancelDefaultToken()

  member x.Cancel() =
        Async.CancelDefaultToken()

I have read few F# tutorials and I have noticed how easy is to perform asynchronous and parallel programming in F# compared to C#. Thus, I am trying to write an F# library which will be called from C# and take take a C# function (delegate) as a parameter and run it asynchronously.

I have managed to pass the function so far (I am even able to cancel) but what I miss is how to implement a callback back to C# which will be executed it as soon as the asynchronous operation is completed. (e.g. the function AsynchronousTaskCompleted?). Also I was wondering if I can post (e.g. Progress %) back to F# from then function AsynchronousTask.

Can someone please help me?

This is the code I have written so far (I am not familiar with F# so the following code may be wrong or poorly implemented).

//C# Code Implementation (How I make the calls/handling)
        //Action definition is: public delegate void Action();
        Action action = new Action(AsynchronousTask);
        Action cancelAction = new Action(AsynchronousTaskCancelled);
        myAsyncUtility.StartTask2(action, cancelAction);
        Debug.WriteLine("0. The task is in progress and current thread is not blocked");
        ......
        private void AsynchronousTask()
        {
            //Perform a time-consuming task
            Debug.WriteLine("1. Asynchronous task has started.");
            System.Threading.Thread.Sleep(7000);
            //Post progress back to F# progress window?
            System.Threading.Thread.Sleep(2000);
        }        
        private void AsynchronousTaskCompleted(IAsyncResult asyncResult)
        {           
            Debug.WriteLine("2. The Asynchronous task has been completed - Event Raised");
        }
        private void AsynchronousTaskCancelled()
        {
            Debug.WriteLine("3. The Asynchronous task has been cancelled - Event Raised");
        }

//F# Code Implementation
  member x.StartTask2(action:Action, cancelAction:Action) = 
        async {
            do! Async.FromBeginEnd(action.BeginInvoke, action.EndInvoke, cancelAction.Invoke)
            }|> Async.StartImmediate
        do printfn "This code should run before the asynchronous operation is completed"    
        let progressWindow = new TaskProgressWindow()
        progressWindow.Run() //This class(type in F#) shows a dialog with a cancel button
        //When the cancel button is pressed I call Async.CancelDefaultToken()

  member x.Cancel() =
        Async.CancelDefaultToken()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

阳光的暖冬 2024-11-08 14:39:57

要获得 F# 异步工作流程的优势,您必须在 F# 中实际编写异步计算。您尝试编写的代码将不起作用(即它可能会运行,但不会有用)。

当您在 F# 中编写异步计算时,可以使用 let!do! 进行异步调用。这允许您使用其他原始的非阻塞计算。例如,您可以使用 Async.Sleep 而不是 Thread.Sleep

// This is a synchronous call that will block thread for 1 sec
async { do Thread.Sleep(1000) 
        someMoreStuff() }

// This is an asynchronous call that will not block threads - it will create 
// a timer and when the timer elapses, it will call 'someMoreStuff' 
async { do! Async.Sleep(1000)
        someMoreStuff() }

您只能在 async 块内使用异步操作,并且它依赖于 F# 编译器处理 do!let! 的方式。对于以顺序方式编写的代码(例如在 C# 中或在 F# 中的 async 块之外),没有(简单)方法可以实现真正的非阻塞执行。

如果您想使用 F# 来获得异步工作流程的优势,那么最好的选择是在 F# 中实现操作,然后使用 Async.StartAsTask 将它们公开给 C#(这为您提供了 Task< ;T> C# 可以轻松使用)。类似这样的事情:

let someFunction(n) = async {
  do! Async.Sleep(n)
  Console.WriteLine("working")
  do! Async.Sleep(n)
  Console.WriteLine("done") 
  return 10 }

type AsyncStuff() = 
  member x.Foo(n) = someFunction(n) |> Async.StartAsTask

// In C#, you can write:
var as = new AsyncStuff()
as.Foo(1000).ContinueWith(op =>
    // 'Value' will throw if there was an exception
    Console.WriteLine(op.Value))

如果您不想使用 F#(至少对于异步计算的实现),那么异步工作流程将无法帮助您。您可以使用 TaskBackgroundWorker 或其他 C# 技术实现类似的功能(但您将失去在不阻塞线程的情况下轻松运行操作的能力)。

To get the benefits of F# asynchronous workflow, you have to actually write the asynchronous computation in F#. The code you're trying to write will not work (i.e. it may run, but won't be useful).

When you're writing asynchronous computations in F#, you can make asynchronous calls using let! and do!. This allows you to use other primitive non-blocking computations. For example, you can use Async.Sleep instead of Thread.Sleep.

// This is a synchronous call that will block thread for 1 sec
async { do Thread.Sleep(1000) 
        someMoreStuff() }

// This is an asynchronous call that will not block threads - it will create 
// a timer and when the timer elapses, it will call 'someMoreStuff' 
async { do! Async.Sleep(1000)
        someMoreStuff() }

You can only use asynchronous operations inside the async block and it relies on the way how F# compiler handles do! and let!. There is no (easy) way to get real non-blocking execution for code that is written in sequential way (e.g. in C# or outside of async block in F#).

If you want to use F# to get the benefits of asynchronous workflows, then the best option is to implement the operations in F# and then expose them to C# using Async.StartAsTask (which gives you Task<T> that C# can easily use). Something like this:

let someFunction(n) = async {
  do! Async.Sleep(n)
  Console.WriteLine("working")
  do! Async.Sleep(n)
  Console.WriteLine("done") 
  return 10 }

type AsyncStuff() = 
  member x.Foo(n) = someFunction(n) |> Async.StartAsTask

// In C#, you can write:
var as = new AsyncStuff()
as.Foo(1000).ContinueWith(op =>
    // 'Value' will throw if there was an exception
    Console.WriteLine(op.Value))

If you don't want to use F# (at least for the implementation of your async computations), then asynchronous workflows won't help you. You can implement similar thing using Task, BackgroundWorker or other C# technologies (but you'll loose the ability to run operations easily without blocking threads).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文