简体   繁体   中英

Async Task.Run Not Working

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:

  1. Does c:\\test\\ exist? If not, you'll get an error.
  2. 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.
  3. Building a long string that way is very inefficient (eg 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 (eg about 20 ms).
  4. (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);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM