I simply wrote below codes and I expect to have 3 text files with async feature in C# but I do not see anything:
private async void Form1_Load(object sender, EventArgs e)
{
Task<int> file1 = test();
Task<int> file2 = test();
Task<int> file3 = test();
int output1 = await file1;
int output2 = await file2;
int output3 = await file3;
}
async Task<int> test()
{
return await Task.Run(() =>
{
string content = "";
for (int i = 0; i < 100000; i++)
{
content += i.ToString();
}
System.IO.File.WriteAllText(string.Format(#"c:\test\{0}.txt", new Random().Next(1, 5000)), content);
return 1;
});
}
There are a few potential issues:
Does c:\test\ exist? If not, you'll get an error.
As written, your Random objects might generate the same numbers, since the current system time is used as the seed, and you are doing these at about the same time. You can fix this by making them share a static Random instance. Edit: but you need to synchronize the access to it somehow. I chose a simple lock on the Random instance, which isn't the fastest, but works for this example.
Building a long string that way is very inefficient (e.g. about 43 seconds in Debug mode for me, to do it once). Your tasks might be working just fine, and you don't notice that it's actually doing anything because it takes so long to finish. It can be made much faster by using the StringBuilder class (e.g. about 20 ms).
(this won't affect whether or not it works, but is more of a stylistic thing) you don't need to use the async and await keywords in your test() method as written. They are redundant, since Task.Run already returns a Task<int>.
This works for me:
private async void Form1_Load(object sender, EventArgs e)
{
Task<int> file1 = test();
Task<int> file2 = test();
Task<int> file3 = test();
int output1 = await file1;
int output2 = await file2;
int output3 = await file3;
}
static Random r = new Random();
Task<int> test()
{
return Task.Run(() =>
{
var content = new StringBuilder();
for (int i = 0; i < 100000; i++)
{
content.Append(i);
}
int n;
lock (r) n = r.Next(1, 5000);
System.IO.File.WriteAllText(string.Format(#"c:\test\{0}.txt", n), content.ToString());
return 1;
});
}
Using a different Random instance each time will cause the Random number generation to generate the same number each time!
The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated.
This is because Random uses the computer's time as a seed value but the precision of this is not sufficient for the computer's processing speed.
Use the same Random number generator, example:
internal async Task<int> test()
{
return await Task.Run(() =>
{
string content = "";
for (int i = 0; i < 10000; i++)
{
content += i.ToString();
}
System.IO.File.WriteAllText(string.Format(#"c:\test\{0}.txt",MyRandom.Next(1,5000)), content);
return 1;
});
}
EDIT:
Also Random is not thread safe so you should synchronize access to it:
public static class MyRandom
{
private static Random random = new Random();
public static int Next(int start, int end)
{
lock (random)
{
return random.Next(start,end);
}
}
}
Related
I have been assigned the task of converting a large list (4 million) of ids to usernames. For this purpose I've decided to delegate multiple tasks to my premium proxies.
public class ProxyWorker
{
private static int _proxyCount;
static void Run(List<long> largeList)
{
var taskList = new List<Task>();
for (int i = 0; i < _proxyCount; i++)
{
taskList.Add(Task.Factory.StartNew(() => ConvertOnProxy(i, largeList.Take(1000).ToList())));
}
Task.WaitAll(taskList.ToArray());
}
static void ConvertOnProxy(int proxyId, List<long> idsToConvert)
{
// TODO
}
}
I'm stuck on the part of how would I delegate 1,000 to each task, removing them from the list after they've been select so another thread doesn't take them, and keeping the thread safety?
I understand that my current code just grabs 1,000 items without thinking another task is going to do the exact same thing?
Here's an example of where I would start:
static async Task Test()
{
Queue<int> ids = new Queue<int>(Enumerable.Range(0, 100));
List<Task> tasks = new List<Task>();
for (int i = 0; i < 8; i++)
{
tasks.Add(DoTheThings(ids));
}
await Task.WhenAll(tasks);
}
static async Task DoTheThings(Queue<int> ids)
{
Random rnd = new Random();
int id;
for (;;)
{
lock (ids)
{
if (ids.Count == 0)
{
// All done.
return;
}
id = ids.Dequeue();
}
Debug.WriteLine($"Fetching ID {id}...");
// Simulate variable network delay.
await Task.Delay(rnd.Next(200) + 50);
}
}
I have a console app that is making HTTP queries and adding/updating products in my database according to response. Some fail and need to be retried a few times.
The way I came up with was to use a dictionary to store the product ID and a Task. Then I can check all the task results and re-run.
This is working but it strikes me as inefficient. Tasks are not being re-created until all tasks have finished. It would be more efficient if they were immediately restarted but I can't figure out how to do this. Also every retry involves a query to the database as only the ID is stored.
I made small app that shows how I am currently retrying failed requests.
Can someone suggest a more efficient method for retrying?
class Program
{
private static void Main(string[] args)
{
HttpQuery m = new HttpQuery();
var task = Task.Run(() => m.Start());
Task.WaitAll(task);
Console.WriteLine("Finished");
Console.ReadLine();
}
}
class HttpQuery
{
public async Task Start()
{
// dictionary where key represent reference to something that needs to be processed and bool whether it has completed or not
ConcurrentDictionary<int, Task<bool>> monitor = new ConcurrentDictionary<int, Task<bool>>();
// start async tasks.
Console.WriteLine("starting first try");
for (int i = 0; i < 1000; i++)
{
Console.Write(i+",");
monitor[i] = this.Query(i);
}
// wait for completion
await Task.WhenAll(monitor.Values.ToArray());
Console.WriteLine();
// start retries
// number of retries per query
int retries = 10;
int count = 0;
// check if max retries exceeded or all completed
while (count < retries && monitor.Any(x => x.Value.Result == false))
{
// make list of numbers that failed
List<int> retryList = monitor.Where(x => x.Value.Result == false).Select(x => x.Key).ToList();
Console.WriteLine("starting try number: " + (count+1) + ", Processing: " + retryList.Count);
// create list of tasks to wait for
List<Task<bool>> toWait = new List<Task<bool>>();
foreach (var i in retryList)
{
Console.Write(i + ",");
monitor[i] = this.Query(i);
toWait.Add(monitor[i]);
}
// wait for completion
await Task.WhenAll(toWait.ToArray());
Console.WriteLine();
count++;
}
Console.WriteLine("ended");
Console.ReadLine();
}
public async Task<bool> Query(int i)
{
// simulate a http request that may or may not fail
Random r = new Random();
int delay = i * r.Next(1, 10);
await Task.Delay(delay);
if (r.Next(0,2) == 1)
{
return true;
}
else
{
return false;
}
}
}
You can create another method and wrap all these ugly retry logic. All of that ugly code goes away :)
public async Task Start()
{
const int MaxNumberOfTries = 10;
List<Task<bool>> tasks = new List<Task<bool>>();
for (int i = 0; i < 1000; i++)
{
tasks.Add(this.QueryWithRetry(i, MaxNumberOfTries));
}
await Task.WhenAll(tasks);
}
public async Task<bool> QueryWithRetry(int i, int numOfTries)
{
int tries = 0;
bool result;
do
{
result = await Query(i);
tries++;
} while (!result && tries < numOfTries);
return result;
}
Here is my code:
private void RunCoinFlip()
{
ToggleControlsUsability();
Task task = new Task(CoinFlippingAnimation);
task.Start();
task.Wait();
ToggleControlsUsability();
flipOutcome = picCoin.Image == coinSideImages[0] ? CoinSides.Heads : CoinSides.Tails;
lblResult.Text = userGuess == flipOutcome ? "Congrats you won!" : "Too bad you lost.";
}
private void ToggleControlsUsability()
{
btnHeads.Enabled = !btnHeads.Enabled;
btnTails.Enabled = !btnTails.Enabled;
}
private void CoinFlippingAnimation()
{
Random rng = new Random();
for (int i = 0; i < 15; i++)
{
int side = rng.Next(0, coinSideImages.Length);
picCoin.Image = coinSideImages[side];
Thread.Sleep(100);
}
}
Basically, the buttons should be frozen during the operation and be unfrozen afterwards, and the coin flipping animation flips the coin. Unfortunately, the GUI is locked up during the animation so you can't move the window or resize.
I've been reading about async and await but I'm not sure if that applies here or how to add it. The different results I try always lead to either blocking, instant unfreezing of controls, or cross-thread execution errors.
There's no need for another thread here, since the time is all being spent in Thread.Sleep and not the random number generation. So, a simple async solution would be:
private async Task RunCoinFlipAsync()
{
ToggleControlsUsability();
await CoinFlippingAnimationAsync();
ToggleControlsUsability();
flipOutcome = picCoin.Image == coinSideImages[0] ? CoinSides.Heads : CoinSides.Tails;
lblResult.Text = userGuess == flipOutcome ? "Congrats you won!" : "Too bad you lost.";
}
private async Task CoinFlippingAnimationAsync()
{
Random rng = new Random();
for (int i = 0; i < 15; i++)
{
int side = rng.Next(0, coinSideImages.Length);
picCoin.Image = coinSideImages[side];
await Task.Delay(100);
}
}
I want to find out how ConcurrentPriorityQueue works, which can be found here on the parallel example page.. The ConcurrentPriorityQueue is in the ParallelExtensionExtras project, under the CoordinationDataStructures folder.
So I wrote a small example that launches a bunch of Tasks which shall insert into the queue in parallel, for two reasons:
See whether it is threadsafe
See how it performs
But after all, only one core of my laptop seems to be working on that issue.
Here is the code:
class Program
{
public static ConcurrentPriorityQueue<int, string> _queue = new ConcurrentPriorityQueue<int, string>();
public static int _itemCount = 100000;
public static int _taskCount = 20;
static void Main(string[] args)
{
Task[] tasks = new Task[_taskCount];
for (int i = 0; i < _taskCount; ++i)
{
int prio = i; // possibly a closure problem here?
var task = Task.Factory.StartNew(() => EnqueueItems(prio));
tasks[i] = task;
}
Task.WaitAll(tasks);
for (int j = 0; j < _taskCount; ++j)
{
Console.WriteLine( j.ToString() + " count= " + _queue.Where(x => x.Key.Equals(j)).Count());
}
Console.ReadKey();
}
private static void EnqueueItems(int prio)
{
for (int i = 0; i < _itemCount; ++i)
{
_queue.Enqueue(prio, i.ToString());
}
}
}
So, the insertion works, but it is slow and only one core gets load.
At the moment my only explanation is that the Queue slows down the whole process
that much which would be aweful for a ConcurrentQueue. And, as it is from Microsoft
itself, I do not expect that.
Any problem with my testcode?
It is only slightly changed from MSDN on waiting for Tasks
Try
Task.Factor.StartNew(..., cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default)
LongRunning helps get the task get started in parallel quicker.
I have code, that create 5 threads. I need wait, until all threads finished their work, and after return value. How can I do this?
public static int num=-1;
public int GetValue()
{
Thread t=null;
for (int i = 0; i <=5; i++)
{
t = new Thread(() => PasswdThread(i));
t.Start();
}
//how wait all thread, and than return value?
return num;
}
public void PasswdThread(int i)
{
Thread.Sleep(1000);
Random r=new Random();
int n=r.Next(10);
if (n==5)
{
num=r.Next(1000);
}
}
Of course this is not a real code. The actual code is much more complicated, so I simplified it.
P.S. Look carefully. I am not use Task, so I can't use method Wait() or WaitAll(). Also I can't use Join(), because Join wait one thread. If they start wait thread, which already finished they work, the will wait infinity.
Make an array of thread like below and call WaitAll function
List<Thread> threads = new List<Thread>();
Thread thread = null;
for (int i = 0; i <=5; i++)
{
t = new Thread(() => PasswdThread(i));
t.Start();
threads.add(t);
}
Thread.WaitAll(thread);
//how wait all thread, and than return value?
return num;
create a ManualResetEvent handle for each your thread, and then call WaitHandle.WaitAll(handles) in your main thread.
static WaitHandle[] handles = new WaitHandle[5];
`
public void PasswdThread(int i)
{
handles[i] = new ManualResetEvent(false);
Thread.Sleep(1000);
Random r=new Random();
int n=r.Next(10);
if (n==5)
{
num=r.Next(1000);
}
handles[i].Set();
}
Get more information on http://msdn.microsoft.com/en-us/library/z6w25xa6.aspx
I think you can use Thread.WaitAll(thread_array) or in other case you can also use Thread.Sleep(100)
In Thread.sleep, 100 is number of milliseconds. So in this case thread would sleep for 100 milliseconds.
And in Thread.WaitAll - thread_Array is array of threads that you wanna wait.
As this question is effectively a duplicate, please see this answer, (code copied below, all credit to Reed Copsey.
class Program
{
static void Main(string[] args)
{
int numThreads = 10;
ManualResetEvent resetEvent = new ManualResetEvent(false);
int toProcess = numThreads;
// Start workers.
for (int i = 0; i < numThreads; i++)
{
new Thread(delegate()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
// If we're the last thread, signal
if (Interlocked.Decrement(ref toProcess) == 0)
resetEvent.Set();
}).Start();
}
// Wait for workers.
resetEvent.WaitOne();
Console.WriteLine("Finished.");
}
}
Aside
Also note that your PasswdThread code will not produce random numbers. The Random object should be declared statically, outside of your method, to produce random numbers.
Additionally you never use the int i parameter of that method.
I would use TPL for this, imo it's the most up to date technique for handling this sort of synchronization. Given the real life code is probably more complex, I'll rework the example slightly:
public int GetValue()
{
List<Task<int>> tasks = new List<Task<int>>();
for (int i = 0; i <=5; i++)
{
tasks.Add(PasswdThread(i));
}
Task.WaitAll(tasks);
// You can now query all the tasks:
foreach (int result in tasks.Select(t => t.Result))
{
if (result == 100) // Do something to pick the desired result...
{
return result;
}
}
return -1;
}
public Task<int> PasswdThread(int i)
{
return Task.Factory.StartNew(() => {
Thread.Sleep(1000);
Random r=new Random();
int n=r.Next(10);
if (n==5)
{
return r.Next(1000);
}
return 0;
});
}
Thread t=null;
List<Thread> lst = new List<Thread();
for (int i = 0; i <=5; i++)
{
t = new Thread(() => PasswdThread(i));
lst.Add(t);
t.Start();
}
//how wait all thread, and than return value?
foreach(var item in lst)
{
while(item.IsAlive)
{
Thread.Sleep(5);
}
}
return num;