Как вызвать и обработать асинхронный рабочий процесс F # из C # - PullRequest
2 голосов
/ 15 апреля 2011

Я прочитал несколько учебных пособий по F # и заметил, насколько легко выполнять асинхронное и параллельное программирование в F # по сравнению с C #. Таким образом, я пытаюсь написать библиотеку F #, которая будет вызываться из C #, взять функцию C # (делегат) в качестве параметра и выполнить ее асинхронно.

Мне уже удалось пройти функцию (я даже могу отменить), но я упускаю то, как реализовать обратный вызов в C #, который будет выполняться после завершения асинхронной операции. (например, функция AsynchronousTaskCompleted?). Также мне было интересно, могу ли я публиковать (например, Progress%) обратно в F # из функции AsynchronousTask.

Может кто-нибудь помочь мне?

Это код, который я написал до сих пор (я не знаком с 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()

1 Ответ

8 голосов
/ 15 апреля 2011

Чтобы получить преимущества асинхронного рабочего процесса 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 # или вне блока async в F #).

Если вы хотите использовать F # дляПолучите преимущества асинхронных рабочих процессов, тогда лучшим вариантом будет реализовать операции в F #, а затем представить их на C #, используя Async.StartAsTask (что дает вам 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 # (по крайней мере, для реализации ваших асинхронных вычислений), то асинхронные рабочие процессы вам не помогут.Вы можете реализовать аналогичную вещь, используя Task, BackgroundWorker или другие технологии C # (но вы потеряете возможность легко выполнять операции без блокировки потоков).

...