Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task.WaitAll(taskList.ToArray()) never fisnishes #94

Open
Dash83UPV opened this issue Apr 3, 2024 · 3 comments
Open

Task.WaitAll(taskList.ToArray()) never fisnishes #94

Dash83UPV opened this issue Apr 3, 2024 · 3 comments

Comments

@Dash83UPV
Copy link

Dear all
As always, thank you for your hard work

Maybe I'm doing something wrong, but I think I have found an issue.

Launching several tasks to Create several tweets in parallel and using Task.WaiAll() does not work correctly

I have been using the latest 0.40 version with Core NET 8.0
SurrealDB (latest version 1.3.1) is the table tweets with no records.

This is the test code I have prepared.


private static async Task Main(string[] args)
{
    DataBaseParams dbParams = new DataBaseParams()
    {
        ipAddress = "192.168.0.1",
        port = 8000,
        username = "root",
        password = "root",
        database = "testdb",
        dataBaseEngine = DataBaseEngine.SurrealDB
    };

    var surrealDBClient = new SurrealDbClient(
                    SurrealDbOptions
                        .Create()
                        .WithEndpoint($"ws://{dbParams.ipAddress}:{dbParams.port}/rpc")
                        .WithUsername(dbParams.username)
                        .WithPassword(dbParams.password)
                        .WithNamespace(dbParams.database)
                        .WithDatabase(dbParams.database)
                        .Build(),
                    null,
                    (_options) =>
                    {
                        _options.IncludeFields = true;
                    }
    );

    List<Tweet> tweets = new List<Tweet>();
    for (int iCount = 0; iCount < 5; iCount++)
    {
        tweets.Add(new Tweet()
        {
            id = $"ID{iCount}",
            username = $"user{iCount}",
        });
    }

    List<Task<Tweet>> list = new List<Task<Tweet>>();
    tweets.ForEach(tweet =>
    {
        var task = surrealDBClient.Create("tweets2", tweet);
        //var task = dummyTask();
        list.Add(task);
    });

    Task.WaitAll(list.ToArray());
}




Please notice there are 2 methods. One is the basic SurrealDB Create method

var task = surrealDBClient.Create("tweets2", tweet);

The other is a dummy method used to compare the execution.

var task = dummyTask();

private static async Task<Tweet> dummyTask()
{
   await Task.Delay(2000);
   return new Tweet()
   {
       id = "dummy",
       username = "pepito"
   };
}

When I use the code with the Create the execution is stuck on the Task.WaitAll() forever, but checking the DB with Surrealist I can see that the 5 records were inserted.

When I use the code with the DummyTask the execution continues and the program finishes.

I have not tested the code with HTTP instead of WS, but it could have the same behaviour.

@Odonno
Copy link
Contributor

Odonno commented Apr 3, 2024

Hello Alfonso,

I can reproduce this issue. It stops responding on WS calls but works fine on HTTP calls. The root cause it that you are using Task.WaitAll instead of Task.WhenAll.

I am not sure of what you want to do but one major difference between the two methods is that WaitAll is synchronous hence blocking the current (main/UI) thread. WhenAll is asynchronous and return a Task, you can call it anytime you want without blocking the main thread.

In general, it is a best practice to use WhenAll instead of WaitAll unless you really want to use it.

Like you, I wasn't expecting this behavior because I have to consume an Observable that seems to be blocked by another task that runs on the current thread. This can lead to some issue. I am curious to see if a migration to a Channel fixes this (among other things). I do not think this is much important. Can you confirm that WhenAll is a valid usage for you?

Thanks for raising this issue.

@Dash83UPV
Copy link
Author

Hello Odonno

As you said, by modifying my code from

Task.WaitAll(list.ToArray());

to

await Task.WhenAll(list.ToArray());

it works. For now I think I can work with it.

Unfortunately, I just tested the parallelization of several Create method calls, i.e.:

var tasks = tweets.Select(tweet => surrealDBClient.Create("tweets2", tweet));
await Task.WhenAll(tasks);

against

tweets.ForEach(async tweet => await surrealDBClient.Create("tweets2", tweet));

And the ForEach one is faster for Lists below 5000 records.

Really thank you for your help and fast answer.
I will continue bench-working and testing the API.

Best Regards

@Odonno
Copy link
Contributor

Odonno commented Apr 3, 2024

Yes. It depends on what you need once again. :)

Small article that explains the difference: https://blog.nimblepros.com/blogs/task-whenall-vs-parallel-foreach/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants