Chani Poz
Chani Poz

Reputation: 1463

How to know when an async func has finished c#

I download many urls from the web but I don't know when all the urls have been finished to download. Meanwhile I wrote something, but it seem too me a trash although it works.

In my code I download all the urls from dtPP dataTable and save them to matUrlFharsing array.

Here is my code:

main()
{
    Parallel.For(0, dtPP.Rows.Count, i =>
    {
         string f = "";
         WebClient client = new WebClient();
         client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
         lock (dtPP.Rows[i])
         {
              f = dtPP.Rows[i]["pp_url"].ToString();
         }
         client.DownloadDataAsync(new Uri(f), i);
    });
    while (end)
    {
    }
    DoSomething();
 }


void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            int h = (int)e.UserState;
            page = (int)e.UserState;
            myString = enc.GetString(e.Result);

            lock (matUrlFharsing[h])
            {
                lock (dtPP.Rows[h])
                {
                    //save in mat
                    matUrlFharsing[h] = Pharsing.CreateCorrectHtmlDoc(myString);
                }
            }

            lock (myLocker)
            {
                ezer = false;
                for (int j = 0; j < matUrlFharsing.Length && !ezer; j++)
                {
                    if (matUrlFharsing[j] == "")
                        ezer = true;
                }
                end = ezer;
            }
        }

What can I do to improve or change it?

Upvotes: 2

Views: 449

Answers (3)

Dmitrii Dovgopolyi
Dmitrii Dovgopolyi

Reputation: 6301

You can use array of AutoResetEvent, send them to event receiver as parameter and wait them all.

AutoResetEvent[] autoResetEvents;
main()
{
    autoResetEvent = new AutoResetEvent[dtPP.Rows.Count];
    Parallel.For(0, dtPP.Rows.Count, i =>
    {
         string f = "";
         WebClient client = new WebClient();
         client.DownloadDataCompleted += new DownloadDataCompletedEventHandler(client_DownloadDataCompleted);
         lock (dtPP.Rows[i])
         {
              f = dtPP.Rows[i]["pp_url"].ToString();
         }
         Object[] parameters = new Object[2];
         autoResetEvents[i] = new AutoResetEvent(false);
         parameters[0] = i;
         parameters[1] = autoResetEvent[i];

         client.DownloadDataAsync(new Uri(f), parameters);
    });
    WaitHandle.WaitAll(autoResetEvents);
    DoSomething();
 }

    void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
    {
        Object[] parameters = (object[])e.UserState;
        autoResetEvent = (AutoResetEvent)parameters[1];
        int h = (int)parameters[0];
        page = (int)e.UserState;
        myString = enc.GetString(e.Result);

        lock (matUrlFharsing[h])
        {
            lock (dtPP.Rows[h])
            {
                //save in mat
                matUrlFharsing[h] = Pharsing.CreateCorrectHtmlDoc(myString);
            }
        }
        autoResetEvent.Set();
    }

Upvotes: 1

Patrick Dubois
Patrick Dubois

Reputation: 47

The completed event is called when the async function is finished. You are in the right path...

You can improve you code in the While (end). This While statement will run very fast. You can:

  • You can a sleep 1s to reduce CPU processing.
  • You can put a timeout in the while to make sure the application is not locked.

Upvotes: 0

Dmitrii Dovgopolyi
Dmitrii Dovgopolyi

Reputation: 6301

Small improvement:

Use AutoResetEvent instead of bool for End.

AutoResetEvent autoResetEvent;

main()
{
    autoResetEvent = new AutoResetEvent(false);
    Parallel.For(0, dtPP.Rows.Count, i =>
    {
        // your code
    });
    autoResetEvent.WaitOne();
    DoSomething();
 }

void client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
   ...
   if(ezer)
   {
       autoResetEvent.Set();
   }

}

Upvotes: 4

Related Questions