私は最近、スレッドプールでスケジュールされる1000のタスクについて、JavaとC#でベンチマークを実行しています。サーバーには4つの物理プロセッサがあり、それぞれに8つのコアがあります。OSはServer2008で、32 GBのメモリがあり、各CPUはXeon x7550 Westmere/Nehalem-Cです。
つまり、Javaの実装は4スレッドでC#よりもはるかに高速ですが、スレッド数が増えるとはるかに遅くなります。また、スレッド数が増えると、C#は反復ごとに速くなったようです。グラフはこの投稿に含まれています:
Java実装は、64ビットのホットスポットJVMで、Java 7を使用し、オンラインで見つけたエグゼキューターサービススレッドプールを使用して作成されました(以下を参照)。また、JVMを並行GCに設定しました。
C#は.net 3.5で記述され、スレッドプールはcodeprojectから取得されました:http: //www.codeproject.com/Articles/7933/Smart-Thread-Pool
(私は以下のコードを含めました)。
私の質問:
1)Javaが遅くなっているのに、C#が速くなっているのはなぜですか?
2)C#の実行時間が大きく変動するのはなぜですか?(これが私たちの主な質問です)
C#の変動は、メモリバスが最大になっていることが原因であるのかどうか疑問に思いました。
コード(ロックのエラーを強調しないでください。これは私の目的とは無関係です):
Java
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PoolDemo {
static long FastestMemory = 2000000000;
static long SlowestMemory = 0;
static long TotalTime;
static long[] FileArray;
static DataOutputStream outs;
static FileOutputStream fout;
public static void main(String[] args) throws InterruptedException, FileNotFoundException {
int Iterations = Integer.parseInt(args[0]);
int ThreadSize = Integer.parseInt(args[1]);
FileArray = new long[Iterations];
fout = new FileOutputStream("server_testing.csv");
// fixed pool, unlimited queue
ExecutorService service = Executors.newFixedThreadPool(ThreadSize);
//ThreadPoolExecutor executor = (ThreadPoolExecutor) service;
for(int i = 0; i<Iterations; i++) {
Task t = new Task(i);
service.execute(t);
}
service.shutdown();
service.awaitTermination(90, TimeUnit.SECONDS);
System.out.println("Fastest: " + FastestMemory);
System.out.println("Average: " + TotalTime/Iterations);
for(int j=0; j<FileArray.length; j++){
new PrintStream(fout).println(FileArray[j] + ",");
}
}
private static class Task implements Runnable {
private int ID;
static Byte myByte = 0;
public Task(int index) {
this.ID = index;
}
@Override
public void run() {
long Start = System.nanoTime();
int Size1 = 10000000;
int Size2 = 2 * Size1;
int Size3 = Size1;
byte[] list1 = new byte[Size1];
byte[] list2 = new byte[Size2];
byte[] list3 = new byte[Size3];
for(int i=0; i<Size1; i++){
list1[i] = myByte;
}
for (int i = 0; i < Size2; i=i+2)
{
list2[i] = myByte;
}
for (int i = 0; i < Size3; i++)
{
byte temp = list1[i];
byte temp2 = list2[i];
list3[i] = temp;
list2[i] = temp;
list1[i] = temp2;
}
long Finish = System.nanoTime();
long Duration = Finish - Start;
FileArray[this.ID] = Duration;
TotalTime += Duration;
System.out.println("Individual Time " + this.ID + " \t: " + (Duration) + " nanoseconds");
if(Duration < FastestMemory){
FastestMemory = Duration;
}
if (Duration > SlowestMemory)
{
SlowestMemory = Duration;
}
}
}
}
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Amib.Threading;
using System.Diagnostics;
using System.IO;
using System.Runtime;
namespace ServerTesting
{
class Program
{
static long FastestMemory = 2000000000;
static long SlowestMemory = 0;
static long TotalTime = 0;
static int[] FileOutput;
static byte myByte = 56;
static System.IO.StreamWriter timeFile;
static System.IO.StreamWriter memoryFile;
static void Main(string[] args)
{
Console.WriteLine("Concurrent GC enabled: " + GCSettings.IsServerGC);
int Threads = Int32.Parse(args[1]);
int Iterations = Int32.Parse(args[0]);
timeFile = new System.IO.StreamWriter(Threads + "_" + Iterations + "_" + "time.csv");
FileOutput = new int[Iterations];
TestMemory(Threads, Iterations);
for (int j = 0; j < Iterations; j++)
{
timeFile.WriteLine(FileOutput[j] + ",");
}
timeFile.Close();
Console.ReadLine();
}
private static void TestMemory(int threads, int iterations)
{
SmartThreadPool pool = new SmartThreadPool();
pool.MaxThreads = threads;
Console.WriteLine("Launching " + iterations + " calculators with " + pool.MaxThreads + " threads");
for (int i = 0; i < iterations; i++)
{
pool.QueueWorkItem(new WorkItemCallback(MemoryIntensiveTask), i);
}
pool.WaitForIdle();
double avg = TotalTime/iterations;
Console.WriteLine("Avg Memory Time : " + avg);
Console.WriteLine("Fastest: " + FastestMemory + " ms");
Console.WriteLine("Slowest: " + SlowestMemory + " ms");
}
private static object MemoryIntensiveTask(object args)
{
DateTime start = DateTime.Now;
int Size1 = 10000000;
int Size2 = 2 * Size1;
int Size3 = Size1;
byte[] list1 = new byte[Size1];
byte[] list2 = new byte[Size2];
byte[] list3 = new byte[Size3];
for (int i = 0; i < Size1; i++)
{
list1[i] = myByte;
}
for (int i = 0; i < Size2; i = i + 2)
{
list2[i] = myByte;
}
for (int i = 0; i < Size3; i++)
{
byte temp = list1[i];
byte temp2 = list2[i];
list3[i] = temp;
list2[i] = temp;
list1[i] = temp2;
}
DateTime finish = DateTime.Now;
TimeSpan ts = finish - start;
long duration = ts.Milliseconds;
Console.WriteLine("Individual Time " + args + " \t: " + duration);
FileOutput[(int)args] = (int)duration;
TotalTime += duration;
if (duration < FastestMemory)
{
FastestMemory = duration;
}
if (duration > SlowestMemory)
{
SlowestMemory = duration;
}
return null;
}
}
}