gpt4 book ai didi

Java vs C# 多线程性能,为什么 Java 变慢了? (包括图表和完整代码)

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:57:19 27 4
gpt4 key购买 nike

我最近一直在 Java 和 C# 上运行基准测试,以在线程池上安排 1000 个任务。服务器有 4 个物理处理器,每个处理器有 8 个内核。操作系统为 Server 2008,内存为 32 GB,每个 CPU 为 Xeon x7550 Westmere/Nehalem-C。

简而言之,Java 实现在 4 个线程时比 C# 快得多,但随着线程数的增加而慢得多。当线程数增加时,C# 似乎每次迭代都变得更快。图表包含在这篇文章中:

Java vs C# with a threadpool size of 4 threads Java vs C# with a threadpool size of 32 threads Peter's Java answer (see below) vs C#, for 32 threads

Java 实现是在 64 位 Hotspot JVM 上编写的,使用 Java 7 并使用我在网上找到的 Executor Service 线程池(见下文)。我还将 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;
}
}
}

最佳答案

您似乎没有像测试语言如何优化未优化代码那样测试线程框架工作。

Java 特别擅长优化无意义的代码,我相信这可以解释语言的差异。随着线程数量的增加,我怀疑瓶颈会转移到 GC 的执行方式或其他一些与您的测试相关的事情上。

Java 也可能会变慢,因为默认情况下它不支持 NUMA。尝试运行 -XX:+UseNUMA 但是,我建议为了获得最佳性能,您应该尝试将每个进程保持在单个 numa 区域,以避免交叉 numa 开销。

你也可以尝试这个稍微优化的代码,它在我的机器上快了 40%

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 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);

PrintStream ps = new PrintStream(fout);
for (long aFileArray : FileArray) {
ps.println(aFileArray + ",");
}
}

static class ThreadLocalBytes extends ThreadLocal<byte[]> {
private final int bytes;

ThreadLocalBytes(int bytes) {
this.bytes = bytes;
}

@Override
protected byte[] initialValue() {
return new byte[bytes];
}
}

private static class Task implements Runnable {

static final int Size1 = 10000000;
static final int Size2 = 2 * Size1;
static final int Size3 = Size1;

private int ID;
private static final ThreadLocalBytes list1b = new ThreadLocalBytes(Size1);
private static final ThreadLocalBytes list2b = new ThreadLocalBytes(Size2);
private static final ThreadLocalBytes list3b = new ThreadLocalBytes(Size3);

static byte myByte = 0;

public Task(int index) {
this.ID = index;
}

@Override
public void run() {
long Start = System.nanoTime();


byte[] list1 = list1b.get();
byte[] list2 = list2b.get();
byte[] list3 = list3b.get();

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;
}
}
}
}

关于Java vs C# 多线程性能,为什么 Java 变慢了? (包括图表和完整代码),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10027779/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com