Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# tasks with dynamic delay

I have a function that needs to process items 3 at a time, and if the total time taken is less than x seconds, the thread should sleep for the remaining seconds before proceeding further.

So I'm doing the following:

    private void ProcessItems()
    {
        for (int i = 0, n = items.Count; i < n; i++)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();

            batch.Add(items[i]);

            if (batch.Count == 3 || i >= items.Count - 3)
            {
                List<Task> tasks = new List<Task>(3);

                foreach (Item item in batch)
                    tasks.Add(Task.Factory.StartNew(() => ProcessItem(item)));

                Task.WaitAll(tasks.ToArray());

                batch.Clear();
            }

            stopwatch.Stop();

            int elapsed = (int)stopwatch.ElapsedMilliseconds;
            int delay = (3000) - elapsed;

            if (delay > 0)
                Thread.Sleep(delay);
        }
    }

The ProcessItem function makes a webrequest and processes the response (callback). This is the function that takes a small amount of time.

However, if I understand tasks correctly, a thread can have multiple tasks. Therefore, if I sleep the thread, other tasks can be affected.

Is there a more efficient way to achieve the above, and can tasks be used within Parallel.Foreach?

like image 306
Ivan-Mark Debono Avatar asked May 22 '26 12:05

Ivan-Mark Debono


2 Answers

Tasks run on automatically managed threads. There is nothing intrinsically wrong with blocking a thread. It is just a little wasteful.

Here is how I would implement this very cleanly:

MyItem[] items = ...;
foreach(MyItem[] itemsChunk in items.AsChunked(3)) {
 Parallel.ForEach(itemsChunk, item => Process(item));
 //here you can insert a delay
}

This wastes not a single thread and is trivially simple. Parallel.ForEach used the current thread to process work items as well, so it does not sit idle. You can add your delay logic as well. Implementing AsChunked is left as an exercise for the reader... This function is supposed to split a list into chunks of the given size (3). The good thing about such a helper function is that it untangles the batching logic from the important parts.

like image 156
usr Avatar answered May 25 '26 02:05

usr


Use

Task.Delay 

instead

    static async Task DoSomeProcess()
    {
        await Task.Delay(3000);
    }

You are right, Thread.Sleep would block other tasks

Yes you can pair async/await pattern with Parallel.

like image 37
MichaC Avatar answered May 25 '26 01:05

MichaC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!