2015-08-21 6 views
1

Я пытаюсь увеличить количество одновременных асинхронных вызовов, которые я могу сделать в C#. В частности, я стараюсь соответствовать производительности, которую я вижу в Node.js.Как увеличить количество одновременных асинхронных вызовов?

Ниже приведены два примера программ, один в C# и один в JavaScript. Оба считывают случайное число байтов в буфер из 10 МБ файла, содержащего случайные числа, а затем выполняют эту операцию 2000 раз асинхронно. Программа JavaScript может делать это примерно 60 000 раз в секунду на моей машине, но программа C# может делать только около 3000. Насколько я могу судить, они делают то же самое, но я понимаю, что есть определенные отличия.

У меня были аналогичные тесты с различными функциями, в том числе спящие в течение небольшого количества времени, и выполнение вставок в кластер Cassandra с использованием драйверов Datastax Cassandra. Последняя функциональность - это то, что я действительно пытаюсь улучшить, поскольку я могу получить около 80 вставок в секунду на C#, но около 5000 в узле.

Может кто-нибудь помочь мне объяснить это несоответствие?

// C# 

class Program 
{ 
    static Random r = new Random(); 

    static void Main(string[] args) 
    { 
     int iterations = 2000; 

     Stopwatch s = new Stopwatch(); 
     s.Start(); 

     var tasks = Enumerable.Range(1, iterations).Select(i => ReadFile()).ToArray(); 
     Task.WaitAll(tasks); 

     s.Stop(); 

     Console.WriteLine("Total elapsed milliseconds was {0}.", s.ElapsedMilliseconds); 
     Console.WriteLine("Total iterations were {0}.", iterations); 
     Console.WriteLine("Total iterations per second was {0}.", iterations/s.Elapsed.TotalSeconds); 
    } 

    static async Task ReadFile() 
    { 
     string path = @"C:\Temp\random.txt"; 
     int readSize = r.Next(512, 10 * 1024); 

     using (StreamReader reader = new StreamReader(path)) 
     { 
      await reader.ReadAsync(new char[readSize], 0, readSize); 
     } 
    } 
} 

// JavaScript 

var fs = require('fs'); 
var now = require('performance-now'); 

var iterations = 2000; 
var startTime = now(); 
var runningIterations = 0; 

for (var i = 1; i <= iterations; i++) { 
    readFile(function() { 
     runningIterations++; 

     if (iterations == runningIterations) { 
      totalTime = (now() - startTime); 
      console.log("Total iterations: " + iterations); 
      console.log("Total time: " + totalTime); 
      console.log("Iterations per second: " + (iterations/(totalTime/1000))); 
     } 
    }); 
} 

function readFile(callback) { 
    var path = "/Temp/random.txt"; 

    fs.open(path, 'r', function (err, fd) { 
     var readSize = Math.floor(Math.random() * 10 * 1024) + 512; 
     var buffer = new Buffer(readSize); 
     fs.read(fd, buffer, 0, readSize, 0, function (err, bytesRead, buffer) { 
      callback(); 
     }); 
    }); 
}; 
+1

Если вы используете downvote, объясните, почему я могу улучшить вопрос. –

+0

Незначительное усиление производительности с помощью 'Parallel.For (...)' над созданием коллекции с помощью 'Enumerable' и ожидающей' Task.WaitAll'. (Я достиг ~ 5134.15/сек) –

+0

@BradChristie Я вижу такое же улучшение - около 5000-6000 итераций в секунду. Он все еще намного ниже 60 000-70 000, который я получаю с Узел. К сожалению, «Parallel.For», похоже, не улучшает мои вызовы Cassandra (что на самом деле является частью причины, по которой я перешел в «Task.WaitAll» изначально). –

ответ

0

Я не совсем уверен, что я считаю, C# медленнее, учитывая следующее:

Запуск сценария узла, я получаю:

Total iterations: 2000 
Total time: 1199.8234639999998 
Iterations per second: 1666.9118916314178 

Запуск вашего C# script, as-is, я получаю:

Total elapsed milliseconds was 1041. 
Total iterations were 2000. 
Total iterations per second was 1920.61576477911. 

Если я реорганизовать его использовать Parallel.For:

static Random r = new Random(); 

void Main() 
{ 
    int iterations = 2000; 

    Stopwatch s = new Stopwatch(); 
    s.Start(); 

    Parallel.For(0, iterations, ReadFile); 

    s.Stop(); 

    Console.WriteLine("Total elapsed milliseconds was {0}.", s.ElapsedMilliseconds); 
    Console.WriteLine("Total iterations were {0}.", iterations); 
    Console.WriteLine("Total iterations per second was {0}.", iterations/s.Elapsed.TotalSeconds); 
} 

// Define other methods and classes here 
static async void ReadFile(int x) 
{ 
    string path = @"C:\Temp\random.txt"; 
    int readSize = r.Next(512, 10 * 1024); 
    using (StreamReader reader = new StreamReader(path)) 
    { 
     await reader.ReadAsync(new char[readSize], 0, readSize); 
    } 
} 

я получаю довольно значительный прирост производительности:

Total elapsed milliseconds was 389. 
Total iterations were 2000. 
Total iterations per second was 5134.14889288497. 

Я также пари, если я кэшировать буфер, во всех сценариях, есть будет еще одним существенным ударом. Но я могу работать только на своей локальной машине. И из того, что я вижу, нет ничего, что заставило бы меня подумать: «О, ничего себе, что-то не так». Я также не знаю вашу среду. : shrug:

+0

Интересно. Ваши результаты больше того, что я ожидал увидеть. Очевидно, что среда будет диктовать большую часть результата, но я не могу объяснить такое огромное несоответствие на моей машине. –

+0

На самом деле, пробуя его на другой машине, я вижу большие капли в версии узла, которые отражены в моих тестах Cassandra. Второй компьютер представляет собой виртуальную машину с двумя ядрами, тогда как мой рабочий стол имеет 8 ядер. Однако производительность C# одинакова между двумя машинами. –

+0

Есть ли уровень кэширования? Существует fs, доступный для кэшей, может быть, это благодетель? –

Смежные вопросы