I have a requirement where a client makes a request to a single web page, this web page needs to retrieve the results from two other web pages.
The two web pages that we are requesting info from carry out a process before returning the result, this process can take a few minutes so rather than starting a web request and waiting for it to return and then starting another I want to fire off both requests in background workers and have the results being generated in parallel.
So my code looks something like this (Pseudo code):
var worker1 = new BackgroundWorker();
var worker2 = new BackgroundWorker();
worker1.DoWork += (s, e) => {
//Web Request done here
};
worker2.DoWork += (s, e) => {
//Web Request done here
};
worker1.RunWorkerAsync();
worker2.RunWorkerAsync();
//Some logic here that basically waits for both to return.
Now I noticed that the results were still taking longer to return than I expected so I did a bit of a test and changed the contents of the Dowork to
using (var sw = new StreamWriter(#"c:\temp\TEST\Worker1.txt"))
{
for (int i = 0; i < 1000000; i++)
{
sw.WriteLine($"{i} - {DateTime.Now.ToLongTimeString()}");
}
}
For brevity I wont copy this back out but assume that the file name is changed to worker2.txt in the second workers DoWork()
Its crude I know, but it works, its takes about 3 seconds to write out the time 1 million times so in the first file I see times ranging from Execution Time to Execution Time + 3 seconds
In the second file I can see times ranging from Execution time + 3 Seconds to Execution Time + 6 seconds.
So it’s clear at this point that one worker is being executed first and then the other, but I cannot see why.
More info about the project - Web forms (This is a requirement I have been given and have to stick to) .net 4.5
**Edited to add : **
After coming back to this problem I have had a look at the pages that I am calling and notice that they have aspcompat=true in the page declaration, which I assume is what is causing the issue (They require this, I cant remove it).
What are my options now? Ideally I want to be able to call these pages to run in parallel, is there any way to still achieve this with the aspcompat set to true?
Editing for future readers
Note that the problem that I described above and the code that was provided were correct, the issue that I had was that the pages that I was calling were set to use ASPCOMPAT which forces webforms to work in STA mode which is what was throwing me off.
In the end the code above did work unchanged, the solution was to put the page with the background workers in a separate web application with its own app pool, that page the n used the background workers to call off to the pages running in aspcompat mode in their application pool - its not ideal, but its what we wanted for the live deployment anyway.
You could skip the BackgroundWorker and use Task.WaitAll() instead.
void Main()
{
Task.WaitAll(FirstRequest(), SecondRequest());
}
// Define other methods and classes here
private async static Task FirstRequest()
{
// Do your work for one of the WebRequests here
await Task.Delay(3000);
Console.WriteLine("Done with 1");
}
private async static Task SecondRequest()
{
// Do your work for the second WebRequest here
await Task.Delay(3000);
Console.WriteLine("Done with 2");
}
Related
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.
I am building an application with WPF and C# and I have run into an odd problem. There are multiple threads in my application, many of which are created through System.Timer timers. There is a particular action I can take that will cause the UI of my application to freeze; my UI will freeze permanently when this happens. The oddest thing about this though is that if I check the number of available threads with Threadpool.GetAvialbaleThreads, the number of available threads will continuously diminish if I don't stop the application. All of the threads in my application are created either via timer or the Task.StartNew method.
There are several parts of my code that spin up new threads, I will try to show all of them here in an abbreviated way.
DataManager.cs
// Two System.Timers.Timer(s) handle generating data values on 3 second and 1.5 second intervals.
_averageTimer = new System.Timers.Timer(1000 * 3);
_averageTimer.Elapsed += GenerateNewAveragePoint;
_averageTimer.Enabled = false;
_flowGenTimer = new System.Timers.Timer(1000 * 1.5);
_flowGenTimer.Elapsed += GenerateNewFlowSet;
_flowGenTimer.Enabled = false;
// I also have a primary work loop in this class which is created via Task
// This function runs continuously
Task.Run(() => ProcessData());
// I also send off a Task to do file I/O about every 3 seconds
Task.Run(() =>
{
lock (_sharedData.FileLock)
{
_continuousFileManager.WriteDataSubset(tmpData);
}
});
// Finally, I have a similar file I/O function to the one above, but it is
// called in the timer which fires every 3 seconds
Task.Run(() =>
{
lock (_sharedData.FileLock)
{
_averageFileManager.WriteDataSubset(tmpData);
}
});
So from this class it appears that I probably utilize a max of 6 threads.
In another class I have 3 calls to Dispatcher.Invoke
AdvancedPanel.cs
// RealtimeDataFlowItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataFlowItems.Insert(0, avgFlow);
});
// RealtimeDataHRItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataHRItems.Insert(0, avgFlow);
});
// RealtimeDataTimeItems is an ObservableCollection
Application.Current.Dispatcher.Invoke(delegate
{
RealtimeDataTimeItems.Insert(0, avgFlow);
});
In another class I have one call to Dispatcher.Invoke
DataInfo.cs
Application.Current.Dispatcher.Invoke(delegate
{
IndicatorPoints = new PointCollection(new[] { /* Removed for brevity */});
}
In another class there are two System.Timers.Timer(s) which execute at intervals of 15 ms and 2 seconds.
PlotData.cs
_plotTimer = new System.Timers.Timer(15);
_plotTimer.Elapsed += ProcessLoop;
_plotTimer.Enabled = false;
_boundsTimer = new System.Timers.Timer(1000 * 2);
_boundsTimer.Enabled = false;
_boundsTimer.Elapsed += CheckYAxisBounds;
Also, this class utilizes the OxyPlot plotting library in order to present realtime data in the UI. OxyPlot obviously has to modify the UI, so will be performing actions on the UI thread.
As a final note, I use Caliburn.Micro in my application and make use of its EventAggregator heavily. Each time I wish to publish a message a new Task is started with the StartNew method. Nearly all of the classes in my application make use of the EventAggregator in some capacity, so there are several threads that become utilized from these actions.
I hope this information is helpful, please let me know if there is more that I should provide. I am hoping that one of you could provide me any insight on what might be happening, and how I might be able to go about debugging and solving my UI freezing issue. Thank you so much for your help!
I have console application which is doing multiple API requests over HTTPs.
When running in single thread it can do maximum of about 8 API requests / seconds.
Server which is receiving API calls has lots of free resources, so it should be able to handle many more than 8 / sec.
Also when I run multiple instances of the application, each instance is still able to do 8 requests / sec.
I tried following code to parallelize the requests, but it still runs synchronously:
var taskList = new List<Task<string>>();
for (int i = 0; i < 10000; i++)
{
string threadNumber = i.ToString();
Task<string> task = Task<string>.Factory.StartNew(() => apiRequest(requestData));
taskList.Add(task);
}
foreach (var task in taskList)
{
Console.WriteLine(task.Result);
}
What am I doing wrong here?
EDIT:
My mistake was iterating over tasks and getting task.Result, that was blocking the main thread, making me think that it was running synchronously.
Code which I ended up using instead of foreach(var task in taskList):
while (taskList.Count > 0)
{
Task.WaitAny();
// Gets tasks in RanToCompletion or Faulted state
var finishedTasks = GetFinishedTasks(taskList);
foreach (Task<string> finishedTask in finishedTasks)
{
Console.WriteLine(finishedTask.Result);
taskList.Remove(finishedTask);
}
}
There could be a couple of things going on.
First, the .net ServicePoint class allows a maximum number of 2 connections per host by default. See this Stack Overflow question/answer.
Second, your server might theoretically be able to handle more than 8/sec, but there could be resource constraints or other issues preventing that on the server side. I have run into issues with API calls which theoretically should be able to handle much more than they do, but for whatever reason were designed or implemented improperly.
#theMayer is kinda-sorta correct. It's possible that your call to apiRequest is what's blocking and making the whole expression seem synchronous...
However... you're iterating over each task and calling task.Result, which will block until the task completes in order to print it to the screen. So, for example, all tasks except the first could be complete, but you won't print them until the first one completes, and you will continue printing them in order.
On a slightly different note, you could rewrite this little more succinctly like so:
var screenLock = new object();
var results = Enumerable.Range(1, 10000)
.AsParallel()
.Select(i => {
// I wouldn't actually use this printing, but it should help you understand your example a bit better
lock (screenLock) {
Console.WriteLine("Task i");
}
apiRequest(requestedData));
});
Without the printing, it looks like this:
var results = Enumerable.Range(1, 10000)
.AsParallel()
.Select(i => apiRequest(requestedData));
First off I apologize for terrible wording of that question...here's the scenario:
I built a WEB API method that receives a ProductID and then uploads that products images to Amazon S3. This part is working just fine.
I am now trying to get a console app running that will grab a range of ProductIDs and loop through them, calling the API method, and not wait for the results...
Can anyone point me in the right direction?
I suppose another caveat would be to not eat up all the resources on the machine running the console app...so maybe a thread cap?
UPDATE (This still seems to be synchronous):
class Program
{
async static void DoUpload(int itemid)
{
Console.WriteLine("Starting #:" + itemid);
Thread.Sleep(2000); //Simulates long call to API
Console.WriteLine("Finishing #:" + itemid);
}
static void Main(string[] args)
{
for (int i = 0; i < 20; i++)
{
DoUpload(i);
}
}
}
There are a couple easy ways to do this.
I'd recommend using Parallels. It makes the most optimized use of your environments many threads/cores. For your example, you'd simply do something like this:
var status = Parallel.For(0, 20, DoUpload);
while (!status.IsCompleted)
{
//Do something while you wait
}
The other method would be to use Tasks, and send each call as a separate task. Be careful with this approach though because you could overload the system with pending tasks if you have too many iterations.
List<Tasks> tasks = new List<Tasks>();
for (int i = 0; i < 20; i++)
{
var task = Task.Run(() => DoUpload(i));
tasks.Add(task);
}
//wait for completion of all tasks
Task.WaitAll(tasks.ToArray());
I do not recommend using Parallel.For. It does not give an satisfactory control of parallelism (you probably don't want to hammer away hundrades of requests which will start to timeout) also it requires unnecessary context switching.
Threads/cores isn't the limiting factor in case http requests.
In the example change
Thread.Sleep(2000)
to
await Task.Delay(2000)
and when using real web api calls
await httpClient.PostAsync(...)
also remember to wait in Main
Console.ReadLine() // or something more sophisticated
otherwise the program will terminate before the calls have been made.
Then to control the level of parallelism I think the easiest solution is to use a Semaphore to count the number of outstanding calls, waiting in the main loop for the semaphore to be signaled again before issuing new requests.
I'm writing an application in C#, and I am creating multiple BackgroundWorker threads to grab information from webpages. Despite them being BackgroundWorkers, my GUI Form is becoming unresponsive.
When I am debugging, I pause when the program goes unresponsive, and I can see that I am in the Main Thread, and I am paused on the webpage fetching method. This method is only called from new threads, though, so I can’t figure out why I would be there in the Main Thread.
Does this make any sense? What can I do to make sure the web requests are only being handled in their respective threads?
EDIT: some code and explanation
I am processing a large list of addresses. Each thread will be processing one or more addresses. I can choose how many threads I want to create (I keep it modest :))
//in “Controller” class
public void process()
{
for (int i = 1; i <= addressList.Count && i<= numthreads; i++)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += doWork;
bw.RunWorkerAsync((object)i);
}
}
public void doWork(object sender, DoWorkEventArgs e)
{
//create an object that has the web fetching method, call it WorkObject
//WorkObject keeps a reference to Controller.
//When it is done getting information, it will send it to Controller to print
//generate a smaller list of addresses to work on, using e.Argument (should be 'i' from the above 'for' loop)
WorkObject.workingMethod()
}
When WorkObject is created, it uses “i” to know what thread number it is. It will use this to get a list of web addresses to get information from (from a larger list of addresses which is shared by the main Form, the Controller, and each of the WorkObjects – each thread will process a smaller list of addresses). As it iterates over the list, it will call the “getWebInfo” method.
//in “WorkObject” class
public static WebRequest request;
public void workingMethod()
{
//iterate over the small list of addresses. For each one,
getWebInfo(address)
//process the info a bit...then
myController.print()
//note that this isn’t a simple “for” loop, it involves event handlers and threading
//Timers to make sure one is done before going on to the next
}
public string getWebInfo (string address)
{
request = WebRequest.Create(address);
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string content = reader.ReadToEnd();
return content;
}
You should be performing all the web-work in your BackgroundWorker's DoWork event, are you?
Some clipped code may help us to understand what's going on.
In a similar situation I found I had better control by creating my own threads (no BackgroundWorker and no ThreadPool) and throttling the number of active connections. Write the IP addresses to a Queue and then pick each one off, passing it to a helper class where you call its DoSomething method on a new thread. Throttle by incrementing a counter when you launch a thread and decrement it when the thread completes. You can use callback routines from your helper class to signal your UI thread to update the interface or indicate a thread is finished.
Use your UI to vary the throttle limit and watch the Task Manager to see the effect on memory and CPU usage. You can add a maxconnection setting in your app.config to get more simultaneous connections.
I couldn't figure out why the background workers were causing hanging, but instead of using synchronous HTTP requests I switched to asynchronous using this guide:
http://www.developerfusion.com/code/4654/asynchronous-httpwebrequest/
Cleared up all the hanging. Thanks for the responses.