C#多线程-系统的性能和体系结构
因此,我正在开发一个C#应用程序,它相当占用CPU 目前我正在使用ThreadPool异步处理任务,但事实证明这并不像我预期的那样有效 以这个类为例,我使用它检索一个构建器类来生成一个块C#多线程-系统的性能和体系结构,c#,multithreading,performance,C#,Multithreading,Performance,因此,我正在开发一个C#应用程序,它相当占用CPU 目前我正在使用ThreadPool异步处理任务,但事实证明这并不像我预期的那样有效 以这个类为例,我使用它检索一个构建器类来生成一个块 public class ChunkBuilderProvider { private readonly BlockingCollection<ChunkBuilder> Builders; public ChunkBuilderProvider() { B
public class ChunkBuilderProvider
{
private readonly BlockingCollection<ChunkBuilder> Builders;
public ChunkBuilderProvider()
{
Builders = new BlockingCollection<ChunkBuilder>();
for (int i = 0; i < Configs.BuilderMaxInstance; i++)
Builders.Add(new ChunkBuilder());
}
public ChunkBuilder GetBuilder()
{
ChunkBuilder c;
return Builders.TryTake(out c, -1) ? c : null;
}
public void ReplaceBuilder(ChunkBuilder c)
{
Builders.Add(c);
}
public int IdleBuilders()
{
return Builders.Count;
}
internal bool Build(Chunk c)
{
if (c.State == Chunk.ChunkState.Generating)
return false;
var b = GetBuilder();
if (b == null)
return false;
ThreadPool.QueueUserWorkItem(a =>
{
b.Generate(c);
ReplaceBuilder(b);
});
return true;
}
}
公共类ChunkBuilderProvider
{
私有只读阻止集合生成器;
公共ChunkBuilderProvider()
{
Builders=newblockingcollection();
对于(int i=0;i
{
b、 生成(c);
建筑商(b);
});
返回true;
}
}
生成任务是非常CPU密集型的,使用5个构建器运行它,使我的CPU使用率达到100%
蚂蚁告诉我:
[好像我不能在这里发布图片]
编辑:CPU密集型代码如下:
using System;
using System.Collections.Generic;
using HyroVoxelEngine.Graphics.Primitives;
using HyroVoxelEngine.Voxels.Blocks;
using HyroVoxelEngine.Voxels.Chunks;
using SharpDX;
namespace HyroVoxelEngine.Voxels.Meshing
{
public class GreedyMeshing
{
private static readonly int[][][] VerticesOffset = new int[6][][]
{
//TOP
new int[9][]
{
new int[3] {-1, 1, 1}, new int[3] {0, 1, 1}, new int[3] {1, 1, 1}, new int[3] {-1, 1, 0}, new int[3] {0, 1, 0}, new int[3] {1, 1, 0}, new int[3] {-1, 1, -1},
new int[3] {0, 1, -1}, new int[3] {1, 1, -1}
},
//North
new int[9][]
{
new int[3] {-1, -1, 1}, new int[3] {0, -1, 1}, new int[3] {1, -1, 1}, new int[3] {-1, 0, 1}, new int[3] {0, 0, 1}, new int[3] {1, 0, 1}, new int[3] {-1, 1, 1},
new int[3] {0, 1, 1}, new int[3] {1, 1, 1}
},
//Bottom
new int[9][]
{
new int[3] {-1, -1, -1}, new int[3] {0, -1, -1}, new int[3] {1, -1, -1}, new int[3] {-1, -1, 0}, new int[3] {0, -1, 0}, new int[3] {1, -1, 0}, new int[3] {-1, -1, 1},
new int[3] {0, -1, 1}, new int[3] {1, -1, 1}
},
//SOUTH
new int[9][]
{
new int[3] {-1, 1, -1}, new int[3] {0, 1, -1}, new int[3] {1, 1, -1}, new int[3] {-1, 0, -1}, new int[3] {0, 0, -1}, new int[3] {1, 0, -1}, new int[3] {-1, -1, -1},
new int[3] {0, -1, -1}, new int[3] {1, -1, -1}
},
//West
new int[9][]
{
new int[3] {1, 1, 1}, new int[3] {1, 0, 1}, new int[3] {1, -1, 1}, new int[3] {1, 1, 0}, new int[3] {1, 0, 0}, new int[3] {1, -1, 0}, new int[3] {1, 1, -1},
new int[3] {1, 0, -1}, new int[3] {1, -1, -1}
},
//East
new int[9][]
{
new int[3] {-1, -1, 1}, new int[3] {-1, 0, 1}, new int[3] {-1, 1, 1}, new int[3] {-1, -1, 0}, new int[3] {-1, 0, 0}, new int[3] {-1, 1, 0}, new int[3] {-1, -1, -1},
new int[3] {-1, 0, -1}, new int[3] {-1, 1, -1}
}
};
private Block[][][] Blocks;
private List<int> Index;
private int VOXEL_SIZE = 1;
private Chunk chunk;
private List<VoxelVertex> vertices;
public void SetChunk(Chunk c)
{
chunk = c;
Blocks = c.Blocks;
}
public ChunkPrimitive Greedy()
{
Index = new List<int>(10000);
vertices = new List<VoxelVertex>(8000);
/*
* These are just working variables for the algorithm - almost all taken
* directly from Mikola Lysenko's javascript implementation.
*/
int i, j, k, l, w, h, u, v, n;
var side = VoxelFace.Direction.None;
int[] x = {0, 0, 0};
int[] q = {0, 0, 0};
int[] du = {0, 0, 0};
int[] dv = {0, 0, 0};
/*
* We create a mask - this will contain the groups of matching voxel faces
* as we proceed through the chunk in 6 directions - once for each face.
*/
VoxelFace voxelFace, voxelFace1;
int[] Dimensions = {Chunk.SizeX, Chunk.SizeY, Chunk.SizeZ};
VoxelFace[] mask;
/**
* We start with the lesser-spotted boolean for-loop (also known as the old flippy floppy).
*
* The variable backFace will be TRUE on the first iteration and FALSE on the second - this allows
* us to track which direction the indices should run during creation of the quad.
*
* This loop runs twice, and the inner loop 3 times - totally 6 iterations - one for each
* voxel face.
*/
for (bool backFace = true, b = false; b != backFace; backFace = backFace && b, b = !b)
{
/*
* We sweep over the 3 dimensions - most of what follows is well described by Mikola Lysenko
* in his post - and is ported from his Javascript implementation. Where this implementation
* diverges, I've added commentary.
*/
for (int d = 0; d < 3; d++)
{
/*
* These are just working variables to hold two faces during comparison.
*/
u = (d + 1)%3;
v = (d + 2)%3;
x[0] = 0;
x[1] = 0;
x[2] = 0;
q[0] = 0;
q[1] = 0;
q[2] = 0;
q[d] = 1;
mask = new VoxelFace[Dimensions[u]*Dimensions[v]];
/*
* Here we're keeping track of the side that we're meshing.
*/
if (d == 0)
side = backFace ? VoxelFace.Direction.West : VoxelFace.Direction.East;
else if (d == 1)
side = backFace ? VoxelFace.Direction.Bottom : VoxelFace.Direction.Top;
else if (d == 2)
side = backFace ? VoxelFace.Direction.South : VoxelFace.Direction.North;
/*
* We move through the dimension from front to back
*/
for (x[d] = -1; x[d] < Dimensions[d];)
{
n = 0;
for (x[v] = 0; x[v] < Dimensions[v]; x[v]++)
{
for (x[u] = 0; x[u] < Dimensions[u]; x[u]++)
{
/*
* Here we retrieve two voxel faces for comparison.
*/
voxelFace = (x[d] >= 0) ? getVoxelFace(x[0], x[1], x[2], side) : null;
voxelFace1 = (x[d] < Dimensions[d] - 1) ? getVoxelFace(x[0] + q[0], x[1] + q[1], x[2] + q[2], side) : null;
mask[n++] = ((voxelFace != null && voxelFace1 != null && voxelFace.Equals(voxelFace1))) ? null : backFace ? voxelFace1 : voxelFace;
}
}
x[d]++;
/*
* Now we generate the mesh for the mask
*/
n = 0;
for (j = 0; j < Dimensions[v]; j++)
{
for (i = 0; i < Dimensions[u];)
{
if (mask[n] != null)
{
/*
* We compute the width
*/
for (w = 1; i + w < Dimensions[u] && mask[n + w] != null && mask[n + w].Equals(mask[n]); w++) {}
/*
* Then we compute height
*/
bool done = false;
for (h = 1; j + h < Dimensions[v]; h++)
{
for (k = 0; k < w; k++)
{
if (mask[n + k + h*Dimensions[u]] == null || !mask[n + k + h*Dimensions[u]].Equals(mask[n]))
{
done = true;
break;
}
}
if (done)
break;
}
/*
* Here we check the "transparent" attribute in the VoxelFace class to ensure that we don't mesh
* any culled faces.
*/
if (!mask[n].Transparent)
{
/*
* Add quad
*/
x[u] = i;
x[v] = j;
du[0] = 0;
du[1] = 0;
du[2] = 0;
du[u] = w;
dv[0] = 0;
dv[1] = 0;
dv[2] = 0;
dv[v] = h;
/*
* And here we call the quad function in order to render a merged quad in the scene.
*
* We pass mask[n] to the function, which is an instance of the VoxelFace class containing
* all the attributes of the face - which allows for variables to be passed to shaders - for
* example lighting values used to create ambient occlusion.
*/
Quad(new Vector3(x[0], x[1], x[2]), new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]),
new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]), new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]), w, h,
mask[n], backFace);
}
/*
* We zero out the mask
*/
for (l = 0; l < h; ++l)
{
for (k = 0; k < w; ++k)
mask[n + k + l*Dimensions[u]] = null;
}
/*
* And then finally increment the counters and continue
*/
i += w;
n += w;
}
else
{
i++;
n++;
}
}
}
}
}
}
if (vertices.Count == 0 || Index.Count == 0)
return null;
return new ChunkPrimitive(vertices.ToArray(), Index.ToArray());
}
private VoxelFace getVoxelFace(int x, int y, int z, VoxelFace.Direction side)
{
VoxelFace voxelFace = new VoxelFace(side);
voxelFace.Type = Blocks[x][y][z].Type;
voxelFace.Light = chunk.LightValue[x][y][z];
voxelFace.Side = side;
voxelFace.LightSettings = CountSolidCorner(voxelFace, x, y, z);
return voxelFace;
}
private int[] CountSolidCorner(VoxelFace voxelFace, int x, int y, int z)
{
var side = voxelFace.Side;
int bottomLeft = 0;
int bottomRight = 0;
int TopLeft = 0;
int TopRight = 0;
var pos = new Vector3(x, y, z);
#region TOP BOTOM
//SOUTH = -z
//NORTH = +z
//West = -X
//est = X;
int[][] vertOff = VerticesOffset[(int) side];
if (GetBlockSolid(vertOff[6], x, y, z))
bottomLeft++;
if (GetBlockSolid(vertOff[8], x, y, z))
bottomRight++;
if (GetBlockSolid(vertOff[2], x, y, z))
TopRight++;
if (GetBlockSolid(vertOff[0], x, y, z))
TopLeft++;
if (GetBlockSolid(vertOff[1], x, y, z))
{
TopLeft++;
TopRight++;
}
if (GetBlockSolid(vertOff[7], x, y, z))
{
bottomLeft++;
bottomRight++;
}
if (GetBlockSolid(vertOff[3], x, y, z))
{
TopLeft++;
bottomLeft++;
}
if (GetBlockSolid(vertOff[5], x, y, z))
{
TopRight++;
bottomRight++;
}
if (side == VoxelFace.Direction.Bottom)
return new[] {TopLeft, TopRight, bottomLeft, bottomRight};
if (side == VoxelFace.Direction.Top)
return new[] {bottomLeft, bottomRight, TopLeft, TopRight};
if (side == VoxelFace.Direction.West)
return new[] {bottomLeft, TopLeft, bottomRight, TopRight};
if (side == VoxelFace.Direction.East)
return new[] {bottomRight, TopRight, bottomLeft, TopLeft};
if (side == VoxelFace.Direction.North)
return new[] {TopLeft, bottomLeft, TopRight, bottomRight};
#endregion
//COM x Positivo
//TOP - TR - BR - TL - BL
return new[] {4, 4, 4, 4};
}
private bool GetBlockSolid(int[] offset, int x, int y, int z)
{
x = x + offset[0];
y = y + offset[1];
z = z + offset[2];
if (x < 0 | y < 0 | z < 0)
return true;
if (x >= Chunk.SizeX | y >= Chunk.SizeY | z >= Chunk.SizeZ)
return true;
return !Block.IsSolidBlock(Blocks[x][y ][z ].Type);
}
private void Quad(Vector3 bottomLeft, Vector3 topLeft, Vector3 topRight, Vector3 bottomRight, int width, int height, VoxelFace voxel, bool backFace)
{
BlockTexture texture = new BlockTexture();
Vector2[] UVList = new Vector2[4];
var vert = new VoxelVertex[4];
Vector3 normal = voxel.Normal;
if (voxel.Side == VoxelFace.Direction.Top) {}
//switch (voxel.Side)
//{
// case VoxelFace.Direction.Bottom:
// normal = - Vector3.UnitY;
// texture = TextureHelper.GetTexture(voxel.Type, BlockFaceDirection.YDecreasing);
// UVList = TextureHelper.GetUVMapping((int) texture, BlockFaceDirection.YDecreasing);
// break;
// case VoxelFace.Direction.Top:
// normal = Vector3.UnitY;
// texture = TextureHelper.GetTexture(voxel.Type, BlockFaceDirection.YIncreasing);
// UVList = TextureHelper.GetUVMapping((int) texture, BlockFaceDirection.YIncreasing);
// break;
// case VoxelFace.Direction.West:
// normal = Vector3.UnitX;
// texture = TextureHelper.GetTexture(voxel.Type, BlockFaceDirection.XIncreasing);
// UVList = TextureHelper.GetUVMapping((int) texture, BlockFaceDirection.XIncreasing);
// break;
// case VoxelFace.Direction.East:
// normal = -Vector3.UnitX;
// texture = TextureHelper.GetTexture(voxel.Type, BlockFaceDirection.XDecreasing);
// UVList = TextureHelper.GetUVMapping((int) texture, BlockFaceDirection.XDecreasing);
// break;
// case VoxelFace.Direction.North:
// normal = -Vector3.UnitZ;
// texture = TextureHelper.GetTexture(voxel.Type, BlockFaceDirection.ZDecreasing);
// UVList = TextureHelper.GetUVMapping((int) texture, BlockFaceDirection.ZDecreasing);
// break;
// case VoxelFace.Direction.South:
// normal = Vector3.UnitZ;
// texture = TextureHelper.GetTexture(voxel.Type, BlockFaceDirection.ZIncreasing);
// UVList = TextureHelper.GetUVMapping((int) texture, BlockFaceDirection.ZIncreasing);
// break;
//}
int ic = (Index.Count/6)*4;
int[] indexes = !backFace ? new[] {2, 0, 1, 1, 3, 2} : new[] {2, 3, 1, 1, 0, 2};
vert[0] = new VoxelVertex(bottomLeft*(VOXEL_SIZE), normal, UVList[0], new Vector3(voxel.Light, voxel.LightSettings[0], (int) (voxel.Side)));
vert[1] = new VoxelVertex(bottomRight*(VOXEL_SIZE), normal, UVList[1], new Vector3(voxel.Light, voxel.LightSettings[1], (int) (voxel.Side)));
vert[2] = new VoxelVertex(topLeft*(VOXEL_SIZE), normal, UVList[2], new Vector3(voxel.Light, voxel.LightSettings[2], (int) (voxel.Side)));
vert[3] = new VoxelVertex(topRight*(VOXEL_SIZE), normal, UVList[3], new Vector3(voxel.Light, voxel.LightSettings[3], (int) (voxel.Side)));
if (voxel.LightSettings[0] + voxel.LightSettings[3] > voxel.LightSettings[1] + voxel.LightSettings[2])
indexes = !backFace ? new[] {0, 1, 3, 3, 2, 0} : new[] {0, 2, 3, 3, 1, 0};
//int[] indexes = !backFace ? new[] { 0, 3, 2, 2, 1, 0 } : new[] { 0, 1, 2, 2, 0, 2 };
Index.Add(indexes[0] + ic);
Index.Add(indexes[1] + ic);
Index.Add(indexes[2] + ic);
Index.Add(indexes[3] + ic);
Index.Add(indexes[4] + ic);
Index.Add(indexes[5] + ic);
vertices.Add(vert[0]);
vertices.Add(vert[1]);
vertices.Add(vert[2]);
vertices.Add(vert[3]);
}
internal void Dispose()
{
throw new NotImplementedException();
}
}
}
使用系统;
使用System.Collections.Generic;
使用hyrovoxelnengine.Graphics.Primitives;
使用HyroVoxelEngine.Voxels.Blocks;
使用hyrovoxelnengine.Voxels.Chunks;
使用SharpDX;
命名空间HyroVoxelEngine.Voxels.Meshing
{
公共类GreedyMeshing
{
私有静态只读int[][]VerticesOffset=new int[6][]
{
//顶
新整数[9][]
{
新int[3]{-1,1,1},新int[3]{0,1,1},新int[3]{1,1,1},新int[3]{-1,1,0},新int[3]{0,1,0},新int[3]{1,1,0},新int[3]{-1,1,1,1},
新int[3]{0,1,-1},新int[3]{1,1,-1}
},
//北
新整数[9][]
{
新int[3]{-1,-1,1},新int[3]{0,-1,1},新int[3]{1,-1,1},新int[3]{-1,0,1},新int[3]{0,0,1},新int[3]{1,0,1},新int[3]{-1,1,1},
新int[3]{0,1,1},新int[3]{1,1,1}
},
//底部
新整数[9][]
{
新整数[3]{-1,-1,-1},新整数[3]{0,-1,-1},新整数[3]{1,-1,-1},新整数[3]{-1,-1,0},新整数[3]{0,-1,0},新整数[3]{1,-1,0},新整数[3]{-1,-1,1},
新int[3]{0,-1,1},新int[3]{1,-1,1}
},
//南方
新整数[9][]
{
新int[3]{-1,1,-1},新int[3]{0,1,-1},新int[3]{1,1,-1},新int[3]{-1,0,-1},新int[3]{0,0,-1},新int[3]{1,0,-1},新int[3]{-1,-1},
新整数[3]{0,-1,-1},新整数[3]{1,-1}
},
//西部
新整数[9][]
{
新int[3]{1,1,1},新int[3]{1,0,1},新int[3]{1,-1,1},新int[3]{1,1,0},新int[3]{1,0,0},新int[3]{1,-1,0},新int[3]{1,1,-1},
新int[3]{1,0,-1},新int[3]{1,-1,-1}
},
//东边
新整数[9][]
{
新整数[3]{-1,-1,1},新整数[3]{-1,0,1},新整数[3]{-1,1,1},新整数[3]{-1,-1,0},新整数[3]{-1,0,0},新整数[3]{-1,1,0},新整数[3]{-1,1,1},
新整数[3]{-1,0,-1},新整数[3]{-1,1,-1}
}
};
专用块[][][]块;
私有列表索引;
私有int体素_SIZE=1;
私有块;
私有列表顶点;
公共void集块(块c)
{
chunk=c;
块=c.块;
}
公共组块()
{
索引=新列表(10000);
顶点=新列表(8000);
/*
*这些仅仅是算法的工作变量——几乎所有的变量都被采用了
*直接来自Mikola Lysenko的javascript实现。
*/
int i,j,k,l,w,h,u,v,n;
var side=体素面.Direction.None;
int[]x={0,0,0};
int[]q={0,0,0};
int[]du={0,0,0};
int[]dv={0,0,0};
/*
*我们创建一个遮罩-它将包含匹配体素面的组
*当我们从6个方向穿过区块时-每个面一次。
*/
体素面体素面,体素面1;
int[]维度={Chunk.SizeX,Chunk.SizeY,Chunk.SizeZ};
体素面[]掩模;
/**
*我们从较少斑点的布尔for循环(也称为旧的flippy软盘)开始。
*
*变量backFace在第一次迭代时为TRUE,在第二次迭代时为FALSE-这允许
*我们需要跟踪在创建四边形期间索引应该运行的方向。
*
*这个循环运行两次,内部循环运行3次-总共6次-每个循环一次
*体素脸。
*/
for(bool backFace=true,b=false;b!=backFace;backFace=backFace&&b,b=!b)
{
/*
*我们浏览了3个维度——米科拉·莱森科(Mikola Lysenko)很好地描述了以下大部分内容
*在他的博文中,从他的Javascript实现移植而来
*分歧,我添加了评论。
*/
对于(int d=0;d<3;d++)
{
/*
*这些只是在比较过程中保持两个面的工作变量。
*/
u=(d+1)%3;
v=(d+2)%3;
x[0]=0;
x[
using System.Threading.Tasks;
...
public IEnumerable<Chunk> GetChunks()
{
// Here you can return the whole chunks collection or yield them one by one.
yield return new Chunk();
}
public void DoIt()
{
ChunkBuilder builder = new ChunkBuilder();
ParallelOptions options = new ParallelOptions() {
MaxDegreeOfParallelism = 4
};
Parallel.ForEach(this.GetChunks(), options, chunk => builder.Generate(chunk));
}
Parallel.ForEach(this.GetChunks(), options, chunk => new ChunkBuilder().Generate(chunk));