user17753
user17753

Reputation: 3161

StringBuilder in Async Method

If I fire off multiple async web requests, is it safe to append the result to a global variable, such as a StringBuilder? I know the order is not guaranteed.

  1. Does this cause a lot of Task blocking?

  2. Is this safe?

private static StringBuilder sb = new StringBuilder();

private static async Task AccessTheWebAsync()
{
    HttpClient client = new HttpClient();
    HttpResponseMessage response = await client.GetAsync(@"http://www.google.com/");
    sb.Append(response.StatusCode).Append(Environment.NewLine);        
}

static void Main(string[] args)
{
    List<Task> tasks = new List<Task>();
    for (int i = 0; i < 10; i++)
        tasks.Add(AccessTheWebAsync());
    Task.WaitAll(tasks.ToArray());
    Console.Write(sb.ToString());
    Console.ReadLine();
}

Upvotes: 3

Views: 4300

Answers (1)

Reed Copsey
Reed Copsey

Reputation: 564771

Does this cause a lot of Task blocking?

No. You will wait on all of the tasks to complete, but this is by design. Otherwise, this is a fairly efficient way to write this.

Is this safe?

This is not safe. As documented in StringBuilder: "Any instance members are not guaranteed to be thread safe." (In this case, Append is an instance method.)

Since you're running this in a console application, the Append calls will happen on separate threads. You need some form of synchronization, such as using a lock statement around the Append call.

Note that, if you were to use this same code in a Windows Forms or WPF application, however, the code which runs after await would be scheduled using the initial SynchronizationContext, which would cause it to always run on the UI thread, so you wouldn't have thread synchronization issues. Since it's in a console application, however, the continuations will run on separate threads.

Upvotes: 5

Related Questions