I have a dictionary of usernames, I want to check whether these users can be used for login into a website, but iterating it one by one would last long since it's a huge list, I want it to run in max 10 threads, testing 10 at once.
Dictionary<string, string> test = new Dictionary<string,string>;
test.Add("user1", "pass1");
test.Add("user2", "pass2");
...
test.Add("user999", "pass999");
How do I spawn 10 threads and process it, then combine all the result into a new Dictionary containing only user that pass the login test? Example of the site (not real site, only to demonstrate that this function return true for successful login and false for wrong login).
private bool IsLoginSuccess(string u, string p)
{
WebClient wc = new WebClient();
string str = wc.DownloadString("http://www.samplesite.com?user=" + u + "&pass=" p);
if (str == "1") return true;
return false;
}
Firstly, if you're looking to use lots of connections to a single site, you may well want to tweak the process configuration to allow that - otherwise you'll find you get a bottleneck on the WebClient
. See the <connectionManagement>
app.config element for that.
The simplest approach would probably be to use a ConcurrentDictionary
to collect the results, and Parallel.ForEach
to process the original dictionary in multiple threads. (It's safe to read the dictionary from multiple threads, so long as nothing is writing to it.)
var results = new ConcurrentDictionary<string, string>();
Parallel.ForEach(test,
new ParallelOptions { MaxDegreeOfParallelism = 10 },
pair =>
{
if (IsLoginSuccess(pair.Key, pair.Value))]
{
results[pair.Key] = pair.Value;
}
});
Alternatively, you could do everything with asynchronous requests - easier with C# 5 than C# 4, mind you.
See more on this question at Stackoverflow