Search code examples
c#asynchronoustaskprogressclass-variables

Counter inside asynchronous functions


I'm trying to implement a multiple download function, that would fire and download like 10 files at the same time.

I implemented the IProgress interface too to let me know what's the progress for that.

What I need now is a simple counter inside each of them to say: this is download #1, this is download #2, etc..

I can't do a normal counter since they may all run at the same time and update the counter before me using/storing the value, causing me to have a wrong value or the same value for many of them.

I've looked into the Interlocked class, but I'm just not able to find a suitable implementation for that, that would store a specific number for a each async dynamic function that is triggered.

I'm using the number to store the progress in an array, so I'll just call like:

IProgress<double> progressHandler = new Progress<double>(p => HandleUnitProgressBar(p, downloadIndex));

and let the handler store the progress in the designated cell of the array.

Can anyone point me in the right direction?

Edit #1: Adding code I'm trying to use:

for (int i = 0; i < _downloadList.Count; i++)
            {
                var url = _downloadList.ToArray()[i];
                Task.Factory.StartNew
                (
                    async () =>
                    {
                        try
                        {
                            MegaApiClient client = new MegaApiClient();
                            //client.LoginAnonymous();
                            downloadIndex = i;

                            IProgress<double> progressHandler = new Progress<double>(p => HandleUnitProgressBar(p, downloadIndex));

                            await client.DownloadFileAsync(fileLink, url.Value, progressHandler);
                        }
                        catch (Exception e)
                        {
                            //will add later
                        }
                    }
                , CancellationToken.None
                , TaskCreationOptions.None
                , TaskScheduler.Current
            );
        }

Problem with this code is that by the time it reaches downloadIndex = i, i is already 4 (for 4 simultaneous downloads) whereas I want to send 0,1,2,3 and not 4 to all the handlers.


Solution

  • I don't know if I fully understand your question, but I'll give it a shot. If I understand correctly, you are asking for an integer to be assigned to a request for tracking purposes right? I've done this before while doing a bit of stress testing and sends the requests out in waves of 100. The code looked a little like this:

        static void Main(string[] args)
        {
            var app = new Program();
            var i = 0;
            var j = 0;
            var tasks = new List<Task>();
    
            while (j < 1000)
            {
                tasks.Add(app.CreateOpp(j));
                Console.WriteLine(i);
                if (i == 100)
                {
                    var done = Task.WhenAll(tasks);
                    done.Wait();
                    i = 0;
                    tasks = new List<Task>();
                }
    
                i++;
                j++;
            }
        }
    
            private async Task CreateOpp(int i)
        {
            var client = new RestClient("https...");
            var request = new RestRequest(Method.POST);
            request.AddHeader("Authorization", "Bearer Token");
            request.AddHeader("Content-Type", "application/json");
            var response = await client.ExecuteTaskAsync(request);
    
            Console.WriteLine(i + " Status: " + response.StatusCode);
    
            Console.WriteLine();
        }
    

    After each task completes, instead of having it write to the console like I did on the line that says "Console.WriteLine(i + " Status: " + response.StatusCode);", you can probably just increment some value. Hope this helps or at least leads you down a new path!