How to create an asynchronous method

前端 未结 7 2101
误落风尘
误落风尘 2020-12-22 20:18

I have simple method in my C# app, it picks file from FTP server and parses it and stores the data in DB. I want it to be asynchronous, so that user perform other operations

相关标签:
7条回答
  • 2020-12-22 20:31

    ThreadPool.QueueUserWorkItem is the quickest way to get a process running on a different thread.

    Be aware that UI objects have "thread affinity" and cannot be accessed from any thread other than the one that created them.

    So, in addition to checking out the ThreadPool (or using the asynchronous programming model via delegates), you need to check out Dispatchers (wpf) or InvokeRequired (winforms).

    0 讨论(0)
  • 2020-12-22 20:40

    Here are two links about threading in C#

    • Threading in C#
    • Multi-threading in .NET: Introduction and suggestions

    I'd start to read about the BackgroundWorker class

    0 讨论(0)
  • 2020-12-22 20:45

    In Asp.Net I use a lot of static methods for jobs to be done. If its simply a job where I need no response or status, I do something simple like below. As you can see I can choose to call either ResizeImages or ResizeImagesAsync depending if I want to wait for it to finish or not

    Code explanation: I use http://imageresizing.net/ to resize/crop images and the method SaveBlobPng is to store the images to Azure (cloud) but since that is irrelevant for this demo I didn't include that code. Its a good example of time consuming tasks though

    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();
        }
    }
    

    Or going for threading so you dont have to bother with Delegates

    private static void ResizeImagesAsync(string tempuri, Dictionary<string, string> versions)
    {
        Thread t = new Thread (() => ResizeImages(tempuri, versions, null, null));
        t.Start(); 
    }
    
    0 讨论(0)
  • 2020-12-22 20:46

    You need to use delegates and the BeginInvoke method that they contain to run another method asynchronously. A the end of the method being run by the delegate, you can notify the user. For example:

    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);
        }
    }
    

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

    0 讨论(0)
  • 2020-12-22 20:47

    try this method

    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();
        });
    }
    

    Usage:

    RunAsynchronously( () => { picks file from FTP server and parses it}, 
           () => { Console.WriteLine("Parsing is done"); } );
    
    0 讨论(0)
  • 2020-12-22 20:47

    Any time you're doing something asynchronous, you're using a separate thread, either a new thread, or one taken from the thread pool. This means that anything you do asynchronously has to be very careful about interactions with other threads.

    One way to do that is to place the code for the async thread (call it thread "A") along with all of its data into another class (call it class "A"). Make sure that thread "A" only accesses data in class "A". If thread "A" only touches class "A", and no other thread touches class "A"'s data, then there's one less problem:

    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);
        }
    }
    

    Notice that the only part of AsyncClass that's touched from the outside is its public interface, and the only part of that which is data is CompletionTime. Note that this is only touched after the asynchronous task is complete. This means that nothing else can interfere with the tasks inner workings, and it can't interfere with anything else.

    0 讨论(0)
提交回复
热议问题