V
V
Victor P.2019-01-30 12:22:07
ASP.NET
Victor P., 2019-01-30 12:22:07

How to cook multithreading on tasks?

Good afternoon!
I want to figure out how to work with multithreading based on the Task class.
Unfortunately, on the Internet, almost all examples are either Task.Factory.StartNew or a bunch: the same tasks are shoved into an array and Task.WaitAll is done above it.
I'm interested in the situation when you need to read data from the database in a multi-threaded (not asynchronous) mode;
We create a model in which we place the result:

/// <summary>
    /// Информация о разделах
    /// </summary>
    public class ImgStatisticDto
    {
        /// <summary>
        /// Раздел
        /// </summary>
        public enImg Section { get; set; }

        /// <summary>
        /// Количество не готовых к использованию фото
        /// </summary>
        public int NotReady { get; set; }

        /// <summary>
        /// Общее количество фотографий в разделе
        /// </summary>
        public int Count { get; set; }

        public ImgStatisticDto() { }

        public ImgStatisticDto(enImg section)
        {
            Section = section;
        }
    }

And we write a method that returns a result, for example:
private ImgStatisticDto GetStatistic(enImg section)
        {
            var res = new ImgStatisticDto(section);

            using (var db = ImagesContextFactory.Create(section))
            {
                var count = db.Image.CountAsync();
                var notReady = db.Image.Where(x => !x.IsReady).CountAsync();
                Task.WaitAll(count, notReady);
                res.Count = count.Result;
                res.NotReady = notReady.Result;
            }

            return res;
        }

That is, we make several queries to the database, shove them into Task.WaitAll and put the results into the return type.
This is a fairly common situation and it can be written that way, it looks tolerable. According to the same scheme, you can pull async methods from unrelated services in the controller, do WaitAll, fill in the result and spit out the received data.
Let's analyze this example further, for example, I have several sections for images (my enums) and I want to get such statistics for these sections.
I write something like:
public async Task<IList<ImgStatisticDto>> GetStatistic()
        {
            var res = new List<ImgStatisticDto>();
            foreach(enImg section in Enum.GetValues(typeof(enImg)))
            {
                if (section == enImg.none) continue;
                res.Add(GetStatistic(section));
            }

            return res;
        }

The fact is that in this method the words async and Task do not work. The GetStatistic method is kind of synchronous. And there will be synchronous execution in the loop, despite the fact that requests inside the method will be executed in multi-threaded mode.
And I want the launch of these methods to be also in multi-threaded mode. I just can't figure out how to write it beautifully.

Answer the question

In order to leave comments, you need to log in

4 answer(s)
E
eRKa, 2019-01-30
@Jeer

You are wrong. You do not have parallel execution of tasks in the GetStatistic() method.
This is count.Resultequivalent to
This is a normal synchronous execution.
This is how Task.WaitAll(count, notReady);you launched tasks in parallel, but you won’t get the result from them.
If you want to execute the loop body in different threads in a loop, use Parallel.ForEach

C
CHolfield, 2019-01-30
@CHolfield

try wrapping the code inside the task like this, and then the DBMS will take care of multithreading and the order of requests:

public async Task<IList<ImgStatisticDto>> GetStatistic()
        {
            var res = new List<ImgStatisticDto>();
using (var transaction = context.Database.BeginTransaction())
    {
        try
        {
            foreach(enImg section in Enum.GetValues(typeof(enImg)))
            {
                if (section == enImg.none) continue;
                res.Add(GetStatistic(section));
            }
            transaction.Commit();
        }
        catch (Exception)
        {
            transaction.Rollback();
        }
    }
return res;
        }

P
Peter, 2019-01-30
@petermzg

The mere use of Task does not imply multithreading.
Here is an example proving this. And this article will help you figure it out.

R
Roman, 2019-01-31
@yarosroman

As you were told, Task is not multi-threaded, use Thread to work with threads.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question