如何创建异步方法

时间:2009-07-21 13:34:24

标签: c# asynchronous delegates

我的C#应用​​程序中有简单的方法,它从FTP服务器中挑选文件并解析它并将数据存储在数据库中。我希望它是异步的,以便用户在App上执行其他操作,一旦完成解析,他必须得到消息“解析完成”。

我知道它可以通过异步方法调用来实现,但我不知道该怎么做有人可以帮我吗?

8 个答案:

答案 0 :(得分:75)

您需要使用委托及其包含的BeginInvoke方法异步运行另一个方法。在委托运行的方法结束时,您可以通知用户。例如:

class MyClass
{
    private delegate void SomeFunctionDelegate(int param1, bool param2);
    private SomeFunctionDelegate sfd;

    public MyClass()
    {
        sfd = new SomeFunctionDelegate(this.SomeFunction);
    }

    private void SomeFunction(int param1, bool param2)
    {
        // Do stuff

        // Notify user
    }

    public void GetData()
    {
        // Do stuff

        sfd.BeginInvoke(34, true, null, null);
    }
}

http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

阅读

答案 1 :(得分:19)

尝试这种方法

public static void RunAsynchronously(Action method, Action callback) {
    ThreadPool.QueueUserWorkItem(_ =>
    {
        try {
            method();
        } 
        catch (ThreadAbortException) { /* dont report on this */ } 
        catch (Exception ex) {
        }
        // note: this will not be called if the thread is aborted
        if (callback!= null) callback();
    });
}

用法:

RunAsynchronously( () => { picks file from FTP server and parses it}, 
       () => { Console.WriteLine("Parsing is done"); } );

答案 2 :(得分:6)

每当你做异步的事情时,你就会使用一个单独的线程,一个新线程,或一个从线程池中获取的线程。这意味着您异步执行的任何操作都必须非常小心与其他线程的交互。

一种方法是将异步线程的代码(称之为线程“A”)及其所有数据放入另一个类(称为类“A”)。确保线程“A”仅访问“A”类中的数据。如果线程“A”只接触类“A”,而没有其他线程接触类“A”的数据,那么问题就少了一点:

public class MainClass
{
    private sealed class AsyncClass
    {
        private int _counter;
        private readonly int _maxCount;

        public AsyncClass(int maxCount) { _maxCount = maxCount; }

        public void Run()
        {
            while (_counter++ < _maxCount) { Thread.Sleep(1); }
            CompletionTime = DateTime.Now;
        }

        public DateTime CompletionTime { get; private set; }
    }

    private AsyncClass _asyncInstance;
    public void StartAsync()
    {
        var asyncDoneTime = DateTime.MinValue;
        _asyncInstance = new AsyncClass(10);
        Action asyncAction = _asyncInstance.Run;
        asyncAction.BeginInvoke(
            ar =>
                {
                    asyncAction.EndInvoke(ar);
                    asyncDoneTime = _asyncInstance.CompletionTime;
                }, null);
        Console.WriteLine("Async task ended at {0}", asyncDoneTime);
    }
}

请注意,从外部触及的AsyncClass的唯一部分是其公共接口,而其中唯一的部分是数据CompletionTime。请注意,异步任务完成后,仅触摸 。这意味着没有其他任何东西可以干扰任务内部工作,也不会干扰其他任何事情。

答案 3 :(得分:4)

以下是有关C#

中线程的两个链接

我开始阅读BackgroundWorker class

答案 4 :(得分:4)

在Asp.Net中,我使用了很多静态方法来完成工作。如果它只是我需要无响应或状态的工作,我会做一些简单的事情,如下所示。如您所见,我可以选择调用ResizeImages或ResizeImagesAsync,具体取决于我是否要等待它完成

代码说明:我使用http://imageresizing.net/调整大小/裁剪图像,SaveBlobPng方法是将图像存储到Azure(云),但由于这与此演示无关,因此我没有包含该代码。它是耗时任务的一个很好的例子,但

private delegate void ResizeImagesDelegate(string tempuri, Dictionary<string, string> versions);
private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
    ResizeImagesDelegate worker = new ResizeImagesDelegate(ResizeImages);
    worker.BeginInvoke(tempuri, versions, deletetemp, null, null);
}
private static void ResizeImages(string tempuri, Dictionary<string, string> versions)
{
    //the job, whatever it might be
    foreach (var item in versions)
    {
        var image = ImageBuilder.Current.Build(tempuri, new ResizeSettings(item.Value));
        SaveBlobPng(image, item.Key);
        image.Dispose();
    }
}

或者选择线程,这样你就不必费心去代理

private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
{
    Thread t = new Thread (() => ResizeImages(tempuri, versions, null, null));
    t.Start(); 
}

答案 5 :(得分:1)

ThreadPool.QueueUserWorkItem是让进程在不同线程上运行的最快方法。

请注意,UI对象具有“线程关联性”,并且无法从创建它们的任何线程访问。

因此,除了检查ThreadPool(或通过委托使用异步编程模型)之外,还需要查看Dispatchers(wpf)或InvokeRequired(winforms)。

答案 6 :(得分:0)

最后,您将不得不使用某种线程。它基本上工作的方式是你用一个新线程启动一个函数,它将一直运行到函数结束。

如果您正在使用Windows窗体,那么他们为此设置的一个很好的包装器就是调用后台工作器。它允许您在后台工作而不需要锁定UI表单,甚至可以提供与表单通信并提供进度更新事件的方法。

Background Worker

答案 7 :(得分:0)

.NET为特有的功能添加了新的关键字 async 。您可以从$lookup开始挖掘。使功能突兀的最短的通用方法是更改​​功能 F

Object F(Object args)
{
    ...
    return RESULT;
}

像这样:

async Task<Object> FAsync(Object args)
{
    ...
    await RESULT_FROM_PROMISE;
    ...
    return RESULT;
}

以上代码中最重要的事情是,当您的代码使用 await 关键字时,它将控制权返回给名为 FAsync 的函数,并进行其他计算,直到返回允许值并继续执行功能 FAsync 中的其余代码。