Why Thread.Sleep() is so CPU intensive? - c#

I have an ASP.NET page with this pseduo code:
while (read)
{
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.Flush();
}
Any client who requests this page will start to download a binary file. Everything is OK at this point but clients had no limit in download speed so changed the above code to this:
while (read)
{
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.Flush();
Thread.Sleep(500);
}
Speed problem is solved now, but under test with 100 concurrent clients who connect one after another (3 seconds lag between each new connection) the CPU usage increases when the number of clients increases and when there are 70 ~ 80 concurrent clients CPU reaches 100% and any new connection is refused. Numbers may be different on other machines but the question is why Thread.Sleep() is so CPU intensive and is there any way to speed done the client without CPU rising ?
I can do it at IIS level but I need more control from inside of my application.

Let's take a look at whether Michael's answer seems reasonable.
Now, Michael wisely points out that Thread.Sleep(500) shouldn't cost much in the way of CPU. That's all well and good in theory, but let's see if that pans out in practice.
static void Main(string[] args) {
for(int i = 0; i != 10000; ++i)
{
Thread.Sleep(500);
}
}
Running this, the CPU use of the application hovers around the 0% mark.
Michael also points out that since all the threads that ASP.NET has to use are sleeping, it will have to spawn new threads, and offers that this is expensive. Let's try not sleeping, but doing lots of spawning:
static void Main(string[] args) {
for(int i = 0; i != 10000; ++i)
{
new Thread(o => {}).Start();
}
}
We create lots of threads, but they just execute a null operation. That uses a lot of CPU, even though the threads aren't doing anything.
The total number of threads never gets very high though, because each lives for such a short time. Lets combine the two:
static void Main(string[] args) {
for(int i = 0; i != 10000; ++i)
{
new Thread(o => {Thread.Sleep(500);}).Start();
}
}
Adding this operation that we have shown to be low in CPU use to each thread increases CPU use even more, as the threads mount up. If I run it in a debugger it pushes up to near 100% CPU. If I run it outside of a debugger, it performs a bit better, but only because it throws an out of memory exception before it gets a chance to hit 100%.
So, it isn't Thread.Sleep itself that is the problem, but the side-effect that having all available threads sleep forces more and more threads to be created to handle other work, just as Michael said.

Just a guess:
I don't think it's Thread.Sleep() that's tying up the CPU - it's the fact that you're causing threads to be tied up responding to a request for so long, and the system needs to spin up new threads (and other resources) to respond to new requests since those sleeping threads are no longer available in the thread pool.

Rather than an ASP.NET page you should implement an IHttpAsyncHandler. ASP.NET page code puts many things between your code and the browser that would not be appropriate for transferring binary files. Also, since you're attempting to perform rate limitation, you should use asynchronous code to limit resource usage, which would be difficult in an ASP.NET page.
Creating an IHttpAsyncHandler is fairly simple. Just trigger some asynchronous operations in the BeginProcessRequest method, and don't forget to properly close the context to show you have reached the end of the file. IIS won't be able to close it for you here.
The following is my really bad example of how to perform an an asynchronous operation consisting of a series of steps, counting from 0 to 10, each performed at a 500ms interval.
using System;
using System.Threading;
namespace ConsoleApplication1 {
class Program {
static void Main() {
// Create IO instances
EventWaitHandle WaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); // We don't actually fire this event, just need a ref
EventWaitHandle StopWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
int Counter = 0;
WaitOrTimerCallback AsyncIOMethod = (s, t) => { };
AsyncIOMethod = (s, t) => {
// Handle IO step
Counter++;
Console.WriteLine(Counter);
if (Counter >= 10)
// Counter has reaced 10 so we stop
StopWaitHandle.Set();
else
// Register the next step in the thread pool
ThreadPool.RegisterWaitForSingleObject(WaitHandle, AsyncIOMethod, null, 500, true);
};
// Do initial IO
Console.WriteLine(Counter);
// Register the first step in the thread pool
ThreadPool.RegisterWaitForSingleObject(WaitHandle, AsyncIOMethod, null, 500, true);
// We force the main thread to wait here so that the demo doesn't close instantly
StopWaitHandle.WaitOne();
}
}
}
You'll also need to register your IHttpAsyncHandler implementation with IIS in whichever way is appropriate for your situation.

Its because the thread gets a priority boost every time it yields its time slice. Avoid calling sleep often ( particularly with low values ).

Related

Trying to solve a core affinity problem results in UI stalling under heavy CPU load

I have literally no experience in threading, so bear with me, please.
I'm making a monitoring/testing tool, that monitors hardware sensors and uses affinity masks and for loop to cycle through the cores one by one running a full-load single-core stress test.
The problem is, that when the user starts the test, and affinity is set, instead of assigning just the test method to that core, it assigns the entire program, which means UI can run only on the core that is currently tested and is under full load.
I guess it's clear that UI is just stalling during the test, and labels that output monitoring data are frozen, while it's crucial to have relevant readings during the test because this is the main purpose of this program.
After some research, I figured that I need to use threading but I never worked with it before.
Here is my shortened code. The problem is, that when I use threading on any method that contains labels, it throws the error "Cross-thread operation not valid: Control 'CPUTempTDie' accessed from a thread other than the thread it was created on". I tried to start Report sensors in a new thread, but it doesn't help. I literally tried to start in a new thread every method and label that is involved, but it's either doesn't help or control score (score - is a result returned by TestMethod to compare it with the correct number to confirm stability) or the program just skips some part of the code and just says "Done".
The question is: Is it possible to set just a TestingMethod to a particular core, allowing the rest of the program (including UI) to use any other free core, and if not, what exactly should I start in a new thread to let UI update under the load?
//the method below updates labels and calls ReportSensors method that reads
//sensors on a timer tick
private void Monitoring()
{
sensor.ReportSensors(); //calls Method that reads sensors
//Two labels below are stalling when TestingMethod runs
CPUTempTDie.Value = (int)sensor.CpuTemp;
FrequencyLabel.Text = sensor.CoreFrequency.ToString("0") + "MHz";
}
private int TestingMethod()
{
while (true)
{
//Performs calculations to generate load, returns the "score"
}
if (timer.Elapsed.TotalSeconds > 60)
{
break;
}
return score;
}
private async void PerCoreTest()
{
try
{
await Task.Delay(3000);
for (int i = 0; i < (numberOfCores); i++)
{
coreCounter++;
Thread.BeginThreadAffinity();
SetThreadAffinityMask(GetCurrentThread(), new IntPtr(intptrVal));
//TestingMethod below being called twice, and results from both runs
//are later compared for consistency.
TestingMethod();
iter1 = score / 10000;
TestingMethod();
iter2 = score / 10000;
maxScore = Math.Max(iter1, iter2);
await Task.Delay(1000);
TestLabel.Text = score.ToString();
//Switches to the next thread mask
}
}
finally
{
Thread.EndThreadAffinity();
}
}
private void TestButton_Click(object sender, EventArgs e)
{
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.High;
PerCoreTest();
using (Process p = Process.GetCurrentProcess())
p.PriorityClass = ProcessPriorityClass.Normal;
}
Clarification: My question was closed as a duplicate despite the linked thread doesn't answer my question. I ask to reopen it because:
While "a large number of Remote Calls around 2000 - 3000 calls" mentioned in a linked thread might be heavy on some hardware, it's not the same as hammering the CPU with calculations in the while(true) loop, which squeeze all performance from any kind of hardware living nothing for UI if UI sits on the same core.
Suggested solution in the thread that I allegedly duplicated doesn't resolve the issue, and my original question is completely different: I can not figure out what exactly must be put in a task to make UI run smoothly under the load.
Suggestions from the comments under my thread don't answer the question too. I tried the solution from
Panagiotis Kanavos (see below) but the problem persists:
while (true)
{
await Task.Delay(500);
await Task.Run(() => sesnor.ReportSensors());
}
After researching similar topics it seems like none of them address my particular issue.
You're setting the CPU affinity for the UI thread, then running the test routine on the same thread so it makes sense your UI is hanging during the test. Simplify things and ensure your UI/threading is working properly before you jump into actually performing your test routine.
private int TestingMethod()
{
// set affinity for current thread here when ready
// mock a busy thread by sleeping
System.Threading.Thread.Sleep( 15 * 1000 );
return 42;
}
// don't use `async void`
private async Task PerCoreTest()
{
TestLabel.Text = "Running...";
// we're in the UI thread, so we want to run
// the test in another thread. run a new
// task to do so, await result so the continuation
// will execute back in the UI thread
var score = await Task.Run(() => TestingMethod());
TestLabel.Text = score.ToString();
}
private async Task TestButton_Click(object sender, EventArgs e)
{
await PerCoreTest();
}
Nice and simple. Add something else to the form that updates every second or so or a button you can click to verify the UI is updating properly as the test routine is running.
Once you've verified that the UI isn't locking up, then you may begin adding substance to your test routine. I suggest just getting a working test routine without processor affinity first.
private int TestingMethod()
{
var score = 0;
// set affinity for current thread here when ready
do
{
// your cpu-frying logic
}
while( /* sentinel condition */ )
return score;
}
Again, verify the UI is responsive during the test and you can also verify one of your cores is getting abused. Once all that is verified, you may then set the thread affinity INSIDE the TestingMethod() method's implementation (abstracting it to another method call is fine as well as long as it's called from within the TestingMethod's body and isn't run in a Task or another thread. You can pass the mask into TestingMethod as a parameter from the PerCoreTest method.
This should get you on the right track to doing what you want to do. I suggest you spend some quality time reading about multithreading in general and .NET's threading/asynchronous programming model if you plan on continuing with it in the future.

Executing multiple threads

I am developing Windows Form C# program which reads Excel data from shared drive every 20 minutes (I'm using "Timer") - function "inserting". I want to read multiple Excel files at once because of the performance. For that reason I'm using threads.
Each thread is calling a function (LoadExcelData) which reads data from Excel to ArrayList. I want to know when all threads are finished (when all excel files were loaded to ArrayList) in order to insert this ArrayList to internal database.
I tried with thread[i].Join() but this freezes GUI. I also do not know what would happen if I have 100+ files and for this reason 100+ threads. Would that cause memory exception or some other exception?
//Execute every 20 minutes (Timer). Do not Execute in case previouse run is not finished
void inserting(List<String> excels){
int numOfThreads=excels.length;
Thread[] threads = new Thread[numOfThreads];
for (int index = 0; index < numOfThreads; index++)
{
int i = index;
threads[index] = new Thread(() =>
{
LoadExcelData(excels[i].File_name); //function loads excel data to global array "Weather" which is used later on
});
}
for (int i = 0; i < threads.Length; i++)
{
threads[i].Start(); //start thread
}
for (int i = 0; i < threads.Length; i++)
{
// threads[i].Join(); //this freezes GUI!
}
InsertToDB(object of ArrayList<ClassName>); //insert data which was read from Excels
isRunning=false;//Data was successefully inserted to DB
}
I want to run this every 20 minutes. I'm using Timer:
timer = new System.Windows.Forms.Timer();
timer.Tick += new EventHandler(timerEventHanlder);
timer.Interval = 20 * 60000; // in miliseconds
timer.Start();
private void timerEventHanlder(object sender, EventArgs e)
{
List<String> excels = getExcels();
if (!isRunning){ //in case previous timer even is not finished wait another 20 minutes...
isRunning=true; //flag to true
inserting(excels);
}
}
Is there any better wait to solve above problem?
The UI thread is freezing because you're using a System.Windows.Forms.Timer which fires the timer ticked event on the UI thread; this is useful in that you don't have to Invoke anything on the tick event. Calling Join blocks the calling thread and in your case this is the UI thread.
To avoid this (and since you're not needing to Invoke any UI elements), you can change your System.Windows.Forms.Timer to a System.Timers.Timer, which runs in a thread separate from the UI thread. If you switch to a System.Timers.Timer, you'll need to change some of the syntax in your code (e.g. the Tick event is the Elapsed event instead, etc.).
There's also the System.Thread.Timer and the System.Web.UI.Timer, additionally, you could also spawn a second thread from within the timer tick event to avoid it waiting on the threads within the UI thread, example:
private void timerEventHanlder(object sender, EventArgs e)
{
(new System.Threading.Thread(() => {
List<String> excels = getExcels();
if (!isRunning){ //in case previous timer even is not finished wait another 20 minutes...
isRunning=true; //flag to true
inserting(excels);
}
})).Start();
}
Starting a new thread avoids changing any of your current code and allows you to change it back if you do ever need to invoke anything in the UI.
Answering you're other question though:
I also do not know what would happen if I have 100+ files and for this reason 100+ threads. Would that cause memory exception or some other exception?
Spawning 100+ threads won't cause any exceptions unless your code has a specific exception (like a null delegate passed as the ThreadStart), or if the OS can't create a thread, which if the OS can't create a thread you have bigger problems. It is possible that memory exhaustion could happen since the Thread is a managed object and thus takes up memory (along with an ArrayList, but the amount of memory for 100+ threads (even 1000+) is negligible on any system that is capable of running the .NET framework (even on most embedded systems), so the number of threads won't necessarily be an issue.
Looking at your code, you might want to consider instead of spawning 100+ threads, utilizing the System.Threading.ThreadPool and a System.Threading.CountDownEvent, example:
CountdownEvent Countdown;
void LoadExcelData(object data)
{
// loads excel data to global array "Weather" which is used later on
Countdown.Signal();
}
//Execute every 20 minutes (Timer). Do not Execute in case previouse run is not finished
void inserting(List<object> excels)
{
Countdown = new CountdownEvent(excels.Count);
int i = 0;
while (i < excels.Count) {
ThreadPool.QueueUserWorkItem(LoadExcelData, excels[i++].File_name);
}
Countdown.Wait();
InsertToDB(WeatherList); //insert data which was read from Excels
isRunning = false; //Data was successefully inserted to DB
}
This will utilize the system thread pool to execute your functions and allows .NET to handle the scheduling of the threads to avoid massive resource contention if the number of threads is a lot. You could use other methods to block, like a Mutex or Semaphore, but the CountDownEvent pretty much encapsulates what you'd need to do with other wait objects and joining on the threads from the thread pool.
To be honest though, since you're reading data from Excel files in multiple threads, unless each thread reads the entire contents of the file into RAM then executes the operations that way, you might not see a huge increase in performance. Multi-threaded applications that have heavy I/O usually don't see a huge performance increase unless said I/O is on performance minded equipment or the initial input of the entire file is read into RAM. Just a side note as you're multi-threading with files.
It should also be noted too that utilizing the System.Threading.ThreadPool is ideally for threads you expect to only run for a few seconds or so; if you anticipate that a thread could take longer, you should stick with spawning the threads as you have now. You can still use the CountDownEvent and you don't need an array of threads like you have (you could just just use the (new Thread(function)).Start() syntax).
Hope that can help
The parent thread is going to reach the for loop that joins all the worker threads and wait there until all the threads have finished (and can be joined). If the GUI is running in that same parent thread, execution is not going to return to the GUI until all threads have finished, which is going to be a long time as you've set up timers. Try running the GUI in a different thread.
Edit:
Also on a side note, I'd set your timer lengths to something much shorter while you're debugging to see if it's actually waiting as you expect it to. Then once you have it functioning correctly you can set it back to 20 minutes.

Build an update loop in C# [duplicate]

In a windows form application what is the impact of calling Thread.Sleep(1) as illustrated in the following code:
public Constructor()
{
Thread thread = new Thread(Task);
thread.IsBackground = true;
thread.Start();
}
private void Task()
{
while (true)
{
// do something
Thread.Sleep(1);
}
}
Will this thread hog all of the available CPU?
What profiling techniques can I use to measure this Thread's CPU usage ( other than task manager )?
As stated, your loop will not hog the CPU.
But beware: Windows is not a real-time OS, so you will not get 1000 wakes per second from Thread.Sleep(1). If you haven't used timeBeginPeriod to set your minimum resolution you'll wake about every 15 ms. Even after you've set the minimum resolution to 1 ms, you'll still only wake up every 3-4 ms.
In order to get millisecond level timer granularity you have to use the Win32 multimedia timer (C# wrapper).
No it won't hog the CPU, it will just pause your thread for at least that long. While your thread is paused, the operating system can schedule another, unrelated thread to make use of the processor.
Thread.Sleep(1) as stated will not hog the CPU.
Here is what happens when a thread sleeps (more or less):
Thread.Sleep is translated into a system call, which in turn triggers a trap (an interruption that allows the operating system to take control)
The operating system detects the call to sleep and marks your thread as blocked.
Internally the OS keeps a list of threads that need to be waken up and when it should happen.
Since the thread is no longer using the CPU the OS...
If the parent process has not used up all of its time slice the OS will schedule another thread of the process for execution.
Otherwise another process (or the idle process) will start executing.
When the time is due, your thread will be scheduled again for execution, that doesn't mean it will start executing automatically.
On a final note, I don't exactly know what you are doing but it would seem you're trying to take the role of the scheduler, that is, sleeping to provide the CPU with time to do other things...
In a few cases (very few indeed) it might be all right, but mostly you should let the scheduler do its work, it probably knows more than you do, and can make the work better than you can do it.
Small sleep times should be avoided as a thread giving up its time slice gets a priority boost when resignaled, and that can lead to high context switches. In a multithreaded / server application, this can lead to a thrashing effect as the threads are battling for CPU time. Instead, rely on asynchronous functions and synchronization objects such as critical sections or mutexes / semaphores.
As Bob Nadler mentioned Thread.Sleep(1) does not guarantee a sleep time of 1ms.
Here is an example using the Win32 multimedia timer to force a sleep of 1ms.
[DllImport("winmm.dll")]
internal static extern uint timeBeginPeriod(uint period);
[DllImport("winmm.dll")]
internal static extern uint timeEndPeriod(uint period);
timeBeginPeriod(1);
while(true)
{
Thread.Sleep(1); // will sleep 1ms every time
}
timeEndPeriod(1);
Testing this in a C# GUI application, I found that the application used about 50% of my CPU.
For more discussion on this topic see the following forum thread:
http://www.dotnet247.com/247reference/msgs/57/289291.aspx
This is an old thread that comes up in a lot of my searches, but Win7 has a new scheduler and seems to behave differently than the above.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
DateTime dtEnd = DateTime.Now.AddSeconds(1.0);
int i = 0;
while (DateTime.Now < dtEnd)
{
i++;
Thread.Sleep(1);
}
Console.WriteLine(i.ToString());
i = 0;
long lStart = DateTime.Now.Ticks;
while (i++ < 1000)
Thread.Sleep(1);
long lTmp = (DateTime.Now.Ticks - lStart) / 10000;
Console.WriteLine(lTmp.ToString());
Console.Read();
}
}
}
With the above code, My first result gave 946. So in the timespan of 1 second using 1ms sleeps, I got 946 wake ups. That's very close to 1ms.
The second part asks how long it takes to do 1000 sleep events at 1ms each. I got 1034ms. Again, nearly 1ms.
This was on a 1.8ghz core2duo + Win7 using .Net 4.0
Edit: remember, sleep(x) doesn't mean wake up up at this time, it means wake me up no earlier than this time. It is not guaranteed. Although, you can increase the priority of the thread and Windows should schedule your thread before lower priority threads.
No, it won't hog all available CPU, because a sleeping thread will be switched out by the OS' scheduler when another thread has work to do.
No, it will not. You'll barely see it. Somewhere less than 1000 times a second this thread will wake up and do next to nothing before sleeping again.
Edit:
I had to check. Running on Java 1.5 , this test
#Test
public void testSpeed() throws InterruptedException {
long currentTime = System.currentTimeMillis();
int i = 0;
while (i < 1000)
{
Thread.sleep(1);
i++;
}
System.out.println("Executed in " + (System.currentTimeMillis() - currentTime));
}
Ran at approximately 500 sleeps per second on my 3ghz machine. I suppose C# should be fairly much the same. I assume someone will report back with C# numbers for this intensely important real-world benchmark. There was no observable CPU usage, by the way.
A thread can at most hog one (logical) CPU at a time. And a 1ms sleep will not be hogging. Don't sweat it.
also have a look at this: msdn forum
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace Test
{
public static class Program
{
public static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 10; ++i)
{
sw.Reset();
sw.Start();
Thread.Sleep(50);
sw.Stop();
Console.WriteLine("(default) Slept for " + sw.ElapsedMilliseconds);
TimeBeginPeriod(1);
sw.Reset();
sw.Start();
Thread.Sleep(50);
sw.Stop();
TimeEndPeriod(1);
Console.WriteLine("(highres) Slept for " + sw.ElapsedMilliseconds + "\n");
}
}
[DllImport("winmm.dll", EntryPoint="timeBeginPeriod", SetLastError=true)]
private static extern uint TimeBeginPeriod(uint uMilliseconds);
[DllImport("winmm.dll", EntryPoint="timeEndPeriod", SetLastError=true)]
private static extern uint TimeEndPeriod(uint uMilliseconds);
}
}

Multiple Threads

I post a lot here regarding multithreading, and the great stackoverflow community have helped me alot in understand multithreading.
All the examples I have seen online only deal with one thread.
My application is a scraper for an insurance company (family company ... all free of charge). Anyway, the user is able to select how many threads they want to run. So lets say for example the user wants the application to scrape 5 sites at one time, and then later in the day he choses 20 threads because his computer isn't doing anything else so it has the resources to spare.
Basically the application builds a list of say 1000 sites to scrape. A thread goes off and does that and updates the UI and builds the list.
When thats finished another thread is called to start the scraping. Depending on the number of threads the user has set to use it will create x number of threads.
Whats the best way to create these threads? Should I create 1000 threads in a list. And loop through them? If the user has set 5 threads to run, it will loop through 5 at a time.
I understand threading, but it's the application logic which is catching me out.
Any ideas or resources on the web that can help me out?
You could consider using a thread pool for that:
using System;
using System.Threading;
public class Example
{
public static void Main()
{
ThreadPool.SetMaxThreads(100, 10);
// Queue the task.
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
Console.WriteLine("Main thread does some work, then sleeps.");
Thread.Sleep(1000);
Console.WriteLine("Main thread exits.");
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo)
{
Console.WriteLine("Hello from the thread pool.");
}
}
This scraper, does it use a lot of CPU when its running?
If it does a lot of communication with these 1000 remote sites, downloading their pages, that may be taking more time than the actual analysis of the pages.
And how many CPU cores does your user have? If they have 2 (which is common these days) then beyond two simultaneous threads performing analysis, they aren't going to see any speed up.
So you probably need to "parallelize" the downloading of the pages. I doubt you need to do the same for the analysis of the pages.
Take a look into asynchronous IO, instead of explicit multi-threading. It lets you launch a bunch of downloads in parallel and then get called back when each one completes.
If you really just want the application, use something someone else already spent time developing and perfecting:
http://arachnode.net/
arachnode.net is a complete and comprehensive .NET web crawler for
downloading, indexing and storing
Internet content including e-mail
addresses, files, hyperlinks, images,
and Web pages.
Whether interested or involved in
screen scraping, data mining, text
mining, research or any other
application where a high-performance
crawling application is key to the
success of your endeavors,
arachnode.net provides the solution
you need for success.
If you also want to write one yourself because it's a fun thing to write (I wrote one not long ago, and yes, it is alot of fun ) then you can refer to this pdf provided by arachnode.net which really explains in detail the theory behind a good web crawler:
http://arachnode.net/media/Default.aspx?Sort=Downloads&PageIndex=1
Download the pdf entitled: "Crawling the Web" (second link from top). Scroll to Section 2.6 entitled: "2.6 Multi-threaded Crawlers". That's what I used to build my crawler, and I must say, I think it works quite well.
I think this example is basically what you need.
public class WebScraper
{
private readonly int totalThreads;
private readonly List<System.Threading.Thread> threads;
private readonly List<Exception> exceptions;
private readonly object locker = new object();
private volatile bool stop;
public WebScraper(int totalThreads)
{
this.totalThreads = totalThreads;
threads = new List<System.Threading.Thread>(totalThreads);
exceptions = new List<Exception>();
for (int i = 0; i < totalThreads; i++)
{
var thread = new System.Threading.Thread(Execute);
thread.IsBackground = true;
threads.Add(thread);
}
}
public void Start()
{
foreach (var thread in threads)
{
thread.Start();
}
}
public void Stop()
{
stop = true;
foreach (var thread in threads)
{
if (thread.IsAlive)
{
thread.Join();
}
}
}
private void Execute()
{
try
{
while (!stop)
{
// Scrap away!
}
}
catch (Exception ex)
{
lock (locker)
{
// You could have a thread checking this collection and
// reporting it as you see fit.
exceptions.Add(ex);
}
}
}
}
The basic logic is:
You have a single queue in which you put the URLs to scrape then you create your threads and use a queue object to which every thread has access. Let the threads start a loop:
lock the queue
check if there are items in the queue, if not, unlock queue and end thread
dequeue first item in the queue
unlock queue
process item
invoke an event that updates the UI (Remember to lock the UI Controller)
return to step 1
Just let the Threads do the "get stuff from the queue" part (pulling the jobs) instead of giving them the urls (pushing the jobs), that way you just say
YourThreadManager.StartThreads(numberOfThreadsTheUserWants);
and everything else happens automagically. See the other replies to find out how to create and manage the threads .
I solved a similar problem by creating a worker class that uses a callback to signal the main app that a worker is done. Then I create a queue of 1000 threads and then call a method that launches threads until the running thread limit is reached, keeping track of the active threads with a dictionary keyed by the thread's ManagedThreadId. As each thread completes, the callback removes its thread from the dictionary and calls the thread launcher.
If a connection is dropped or times out, the callback reinserts the thread back into the queue. Lock around the queue and the dictionary. I create threads vs using the thread pool because the overhead of creating a thread is insignificant compared to the connection time, and it allows me to have a lot more threads in flight. The callback also provides a convenient place with which to update the user interface, even allowing you to change the thread limit while it's running. I've had over 50 open connections at one time. Remember to increase your MacConnections property in your app.config (default is two).
I would use a queue and a condition variable and mutex, and start just the requested number of threads, for example, 5 or 20 (and not start 1,000).
Each thread blocks on the condition variable. When woken up, it dequeues the first item, unlocks the queue, works with the item, locks the queue and checks for more items. If the queue is empty, sleep on the condition variable. If not, unlock, work, repeat.
While the mutex is locked, it can also check if the user has requested the count of threads to be reduced. Just check if count > max_count, and if so, the thread terminates itself.
Any time you have more sites to queue, just lock the mutex and add them to the queue, then broadcast on the condition variable. Any threads that are not already working will wake up and take new work.
Any time the user increases the requested thread count, just start them up and they will lock the queue, check for work, and either sleep on the condition variable or get going.
Each thread will be continually pulling more work from the queue, or sleeping. You don't need more than 5 or 20.
Consider using the event-based asynchronous pattern (AsyncOperation and AsyncOperationManager Classes)
You might want to take a look at the ProcessQueue article on CodeProject.
Essentially, you'll want to create (and start) the number of threads that are appropriate, in your case that number comes from the user. Each of these threads should process a site, then find the next site needed to process. Even if you don't use the object itself (though it sounds like it would suit your purposes pretty well, though I'm obviously biased!) it should give you some good insight into how this sort of thing would be done.

C# compact framework : multi thread cause delay?

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.
Two possible causes for the slowness:
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)
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.
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));
}

Categories