I have three tasks like this
public List<CheckResponse> Check(CheckRequest request)
{
var Responses = new List<CheckResponse>();
List<Task> TaskList = new List<Task>();
Task task1 = new Task(() =>
{
Service gatewayObject = new Service();
var response = gatewayObject.Check();
Responses.Add(response);
});
task1.Start();
TaskList.Add(task1);
Task task2 = new Task(() =>
{
Service gatewayObject = new Service();
var response = gatewayObject.Check();
Responses.Add(response);
});
task2.Start();
TaskList.Add(task2);
Task task3 = new Task(() =>
{
Service gatewayObject = new Service();
var response = gatewayObject.Check();
Responses.Add(response);
});
task3.Start();
TaskList.Add(task3);
Task.WaitAll(TaskList.ToArray());
return Responses;
}
Each of them make request to service and can return positive result
so I want to cancel other two task if any of them return positive result.
Service side code is not accessible for me so I can not make any changes on service side.
Related
So I was trying to do a quick performance test against a web api to see how it would handle multiple synchronous HTTP requests at once. I did this by spinning up 30 multiple tasks and have each of them send a http request with the HttpClient. To my surprise, it was extremely slow. I thought it was due to the lack of async/await or the web api was slow, but it turns out it's only when I'm using tasks and synchronous http calls (see TestSynchronousWithParallelTasks() below).
So I did a comparison between using without Tasks, async/await with tasks, and ParallelForEach by making some simple tests. All of these finished quickly around 10-20 milliseconds, but the original case which takes around 20 seconds!
Class: HttpClientTest Passed (5) 19.2 sec TestProject.HttpClientTest.TestAsyncWithParallelTasks Passed 12 ms TestProject.HttpClientTest.TestIterativeAndSynchronous Passed 22 ms TestProject.HttpClientTest.TestParallelForEach Passed 15 ms TestProject.HttpClientTest.TestSynchronousWithParallelTasks Passed 19.1 sec TestProject.HttpClientTest.TestSynchronousWithParallelThreads Passed 10 ms
public class HttpClientTest
{
private HttpClient httpClient;
private readonly ITestOutputHelper _testOutputHelper;
public HttpClientTest(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
ServicePointManager.DefaultConnectionLimit = 100;
httpClient = new HttpClient(new HttpClientHandler { MaxConnectionsPerServer = 100 });
}
[Fact]
public async Task TestSynchronousWithParallelTasks()
{
var tasks = new List<Task>();
var url = "https://localhost:44388/api/values";
for (var i = 0; i < 30; i++)
{
var task = Task.Run(() =>
{
var response = httpClient.GetAsync(url).Result;
var content = response.Content.ReadAsStringAsync().Result;
});
tasks.Add(task);
}
await Task.WhenAll(tasks);
}
[Fact]
public void TestIterativeAndSynchronous()
{
var url = "https://localhost:44388/api/values";
for (var i = 0; i < 30; i++)
{
var response = httpClient.GetAsync(url).Result;
var content = response.Content.ReadAsStringAsync().Result;
}
}
[Fact]
public async Task TestAsyncWithParallelTasks()
{
var url = "https://localhost:44388/api/values";
var tasks = new List<Task>();
for (var i = 0; i < 30; i++)
{
var task = Task.Run(async () =>
{
var response = await httpClient.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
});
tasks.Add(task);
}
await Task.WhenAll(tasks);
}
[Fact]
public void TestParallelForEach()
{
var url = "https://localhost:44388/api/values";
var n = new int[30];
Parallel.ForEach(n, new ParallelOptions { MaxDegreeOfParallelism = 2 }, (i) =>
{
var response = httpClient.GetAsync(url).Result;
var content = response.Content.ReadAsStringAsync().Result;
});
}
[Fact]
public async Task TestSynchronousWithParallelThreads()
{
var tasks = new List<Task>();
var url = "https://localhost:44388/api/values";
var threads = new List<Thread>();
for (var i = 0; i < 30; i++)
{
var thread = new Thread( () =>
{
var response = httpClient.GetAsync(url).Result;
var content = response.Content.ReadAsStringAsync().Result;
});
thread.Start();
threads.Add(thread);
}
foreach(var thread in threads)
{
thread.Join();
}
}
}
So any idea what's causing this performance hit?
I would have expected TestSynchronousWithParallelTasks() to be faster than TestIterativeAndSynchronous() as you'd be starting more requests at once, even if it's IO bound. While the latter is waiting for each request before starting a new one. So it seems like it's related to the tasks somehow blocking each other?
Edit: Added a test case to use threads instead and it's quick like the rest.
This is the C# Code
app.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration();
hubConfiguration.EnableDetailedErrors = true;
app.MapSignalR(hubConfiguration);
CpuEngine cpuEngine = new CpuEngine(1500);
MemoryEngine memoryEngine = new MemoryEngine(1500);
// Task.Factory.StartNew(async () => await cpuEngine.StartCpuCheck());
// Task.Factory.StartNew(async () => await memoryEngine.StartCheckMemory());
Only the first one is running. How can I run each other?
1) Use Task.Run instead.
2) Remove the keywords async and await in the lambda.
3) Use Task.WhenAll and pass in the two tasks.
public async Task InvokeAsync()
{
var cpuEngine = new CpuEngine(1500);
var memoryEngine = new MemoryEngine(1500);
await Task.WhenAll(
Task.Run(() => cpuEngine.StartCpuCheck()),
Task.Run(() => memoryEngine.StartCheckMemory()));
}
Hello I'm wondering if there is a cleaner way of writing the async code below. Basically I want to wait on all the tasks, but one of the tasks are optional. It feels needlessly elaborate, thinking if I can do it through some callback but haven't been able to figure it out.
var mobile = true;
var task1 = _service.Async1();
var tasks = new List<Task>
{
task1
};
Task<int> task2 = null;
if (!mobile)
{
task2 = _service.Async2();
tasks.Add(task2);
}
await Task.WhenAll(tasks);
var result1 = task1.Result;
if (!mobile)
{
result2 = task2.Result;
// Do stuff
}
There is no need to create a list and await all the results at once. Why not await it when you need it? If task2 runs much longer than task1, you can at least start processing it, long before task2 is done.
Something like this:
var task1 = _service.Async1();
Task<int> task2 = null;
if (!mobile)
{
task2 = _service.Async2();
}
var result1 = await task1;
if (!mobile)
{
var result2 = await task2;
// Do stuff
}
i was looking for way out run multiple task and report about task status not sequencially.
here i am pasting a code where multiple task running and reporting when all task complete.
var task1 = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
return "dummy value 1";
});
var task2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(13000);
return "dummy value 2";
});
var task3 = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
return "dummy value 3";
});
Task.Factory.ContinueWhenAll(new[] { task1, task2, task3 }, tasks =>
{
foreach (Task<string> task in tasks)
{
Console.WriteLine(task.Result);
}
});
Console.ReadLine();
task1 will take less time and then task3 will complete and last task2 will complete but ContinueWhenAll always showing task1 is completed and then task2 & task3. i want to modify the code in such way as a result which task complete fast that will show first not sequentially. where to change in code. guide please. thanks
UPDATE
var taskp = Task.Factory.StartNew(() =>
{
var task1 = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
return "Task1 finished";
}).ContinueWith((continuation) => { Console.WriteLine(continuation.Result); });
var task2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
return "Task2 finished";
}).ContinueWith((continuation) => { Console.WriteLine(continuation.Result); });
var task3 = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
return "Task3 finished";
}).ContinueWith((continuation) => { Console.WriteLine(continuation.Result); });
return "Main Task finished";
});
taskp.ContinueWith(t => Console.WriteLine(t.Result));
Console.ReadLine();
An easy solution would be to ContinueWith each task, individually. This is a very quick and dirty example:
var taskp = Task.Factory.StartNew(() =>
{
var task1 = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
return "dummy value 1";
}).ContinueWith((continuation) => { Console.WriteLine("task1"); });
var task2 = Task.Factory.StartNew(() =>
{
Thread.Sleep(3000);
return "dummy value 2";
}).ContinueWith((continuation) => { Console.WriteLine("task2"); });
var task3 = Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
return "dummy value 3";
}).ContinueWith((continuation) => { Console.WriteLine("task3"); });
Task.Factory.ContinueWhenAll(new Task[] { task1, task2, task3}, (x) => { Console.WriteLine("Main Task Complete"); });
});
The code is updated to adapt to OP's UPDATE, with a "Main" task which will output after all the "inner" tasks are complete. To make it so taskp returns the string instead of writing it, the code becomes
var taskp = Task.Factory.StartNew<string>(() =>
{
var task1 = ...; //same
var task2 = ...; //same
var task3 = ...; //same
return "Main Task Complete";
}).ContinueWith((x)=> Console.WriteLine(x.Result));
The StartNew<> overload must be used to specify the return type for the Task to have a Result.
I'll start off by publishing the code that is troubled:
public async Task main()
{
Task t = func();
await t;
list.ItemsSource = jlist; //jlist previously defined
}
public async Task func()
{
TwitterService service = new TwitterService(_consumerKey, _consumerSecret);
service.AuthenticateWith(_accessToken, _accessTokenSecret);
TwitterGeoLocationSearch g = new TwitterGeoLocationSearch(40.758367, -73.982706, 25, 0);
SearchOptions s = new SearchOptions();
s.Geocode = g;
s.Q = "";
s.Count = 1;
service.Search(s, (statuses, response) => get_tweets(statuses, response));
void get_tweets(TwitterSearchResult statuses, TwitterResponse response)
{
//unimportant code
jlist.Add(info);
System.Diagnostics.Debug.WriteLine("done with get_tweets, jlist created");
}
I am having issues with the get_tweets(..) function running (on what I believe a different thread) and the Task t is not awaited like I have in the main function. Basically, my issue is that the list.Itemsource = jlist is ran before the get_tweets function is finished. Does anyone have a solution or the right direction to point me in?
First, create a TAP wrapper for TwitterService.Search, using TaskCompletionSource. So something like:
public static Task<Tuple<TwitterSearchResult, TwitterResponse>> SearchAsync(this TwitterService service, SearchOptions options)
{
var tcs = new TaskCompletionSource<Tuple<TwitterSearchResult, TwitterResponse>>();
service.Search(options, (status, response) => tcs.SetResult(Tuple.Create(status, response)));
return tcs.Task;
}
Then you can consume it using await:
SearchOptions s = new SearchOptions();
s.Geocode = g;
s.Q = "";
s.Count = 1;
var result = await service.SearchAsync(s);
get_tweets(result.Item1, result.Item2);