views:

388

answers:

2

In my mobile app, I want to load all images from an arraylist of links. For each link I create a thread and make httpwebrequest. The problem is that my app run not smooth. It seems to get a delay every time I create new thread and when thread done(when thread done I'll draw the download img onto background). Here's my code:

            for (int i = 0; i < NumbersOfImg; i++)
            {
                if (i < ImgObjArr.Count)
                {
                    ThreadStart myThread = new ThreadStart(getUrlImg);
                    Thread t = new Thread(myThread);
                    t.Start();
                }
            }


     private void getUrlImg()
     {
            MyImage mycurrentImg = (MyImage)ImgObjArr[currentMyImg];
            if (currentMyImg < ImgObjArr.Count - 1)
                currentMyImg++;
            myRequest = (HttpWebRequest)WebRequest.Create(mycurrentImg.ImageLink);
            myResponse = (HttpWebResponse)myRequest.GetResponse();

            Stream ImgStream = myResponse.GetResponseStream();
            mycurrentImg.FullImg = new Bitmap(ImgStream);

            this.BeginInvoke(new EventHandler(ImageUpdate));
    }

and method ImageUpdate() will draw the Image. And when app navigate to next row, I will create numbers of threads to continue make webrequest. And delay happen when the old thread not complete but I create new threads. So any suggestion why my app had delay? Thanks in advance.

+2  A: 

Two possible causes for the slowness:

  1. Depending on the value of ImgObjArr.Count, the code in the question could create a large number of threads, all hogging the CPU. The thread code itself is mostly harmless -- they wait for HTTP responses to come back. If a large number of them is run simultaneously, however, you could get CPU peaks that could slow down the UI. That can happen when the requests are being sent, and when responses start coming back and the code creates the Bitmap objects. Context switching has a cost too.

    What number of threads is too high depends on the horsepower of the CPU in question. Given that this is a compact-framework question, that would be the lower-end of the spectrum. You might want to consider limiting the number of background threads to a fixed pool size. Some number between 2-4 might be right. Note that you will not gain much benefit from more threads if the framework limits the number of outgoing connections anyway. (there should be a default limit set by the framework, 2 connections I believe, which you can change. The OS may set a limit too)

  2. The code inside ImageUpdate executes in the UI thread of the app. Any time spent there is time not available for processing input. This directly contributes to UI delays. If there is any code there that could be pushed into the background thread, that would be a worthwhile exercise. If all code that could be move to the background was already moved, reducing the number of background threads could still help, as that reduces the chance of multiple bitmaps hitting the UI thread at the same time and creating chained delays.

Oren Trutner
At first, thanks much for your reply.So as you suggest, I should limit the threads available at one time. But how about if one webrequest http met the exception of request time out. In default, my app has at first 9 images(and 9 threads) at first. Then each navigate load more 3 threads (3 img each row). Is there any advice for me? Thanks
Thyphuong
A couple of thoughts; if groups of images are always loaded together -- e.g. the 9's, the 3's, or the entire 36 -- it may be more efficient to download a large image containing the images you need as tiles. That will reduce the number of request/reply roundtrips. As for timeouts, a pool of 4 threads should able to deal with an occasional stuck request without much of a user impact. If the service is down or connectivity is lost, any number of threads will just hang there.
Oren Trutner
It's not the group. The images are seperate images from different links.
Thyphuong
+1  A: 

Creating a new thread is actually quite slow, and the more threads you have running at a time on a single processor system the longer each thread takes to operate once started. What you actually need is to limit the number of thread to something sensible and to only start the threads once and from then on just reused them.

Actually Microsoft has already done all the hard work of managing a pool of threads for this kind of task it is called the thread pool. You use it as follows:

for (int i = 0; i < NumbersOfImg; i++)
{
    if (i < ImgObjArr.Count)
    {
        ThreadPool.QueueUserWorkItem(getUrlImg)
    }
}


 private void getUrlImg(object state)
 {
     MyImage mycurrentImg = (MyImage)ImgObjArr[currentMyImg];
     if (currentMyImg < ImgObjArr.Count - 1)
         currentMyImg++;
     myRequest = (HttpWebRequest)WebRequest.Create(mycurrentImg.ImageLink);
     myResponse = (HttpWebResponse)myRequest.GetResponse();

     Stream ImgStream = myResponse.GetResponseStream();
     mycurrentImg.FullImg = new Bitmap(ImgStream);

     this.BeginInvoke(new EventHandler(ImageUpdate));
}
trampster