我正在使用以下代码在C#中制作图像蒙版:
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
bmp.SetPixel(x,y,Color.White);
}
}
for(int x = left; x < width; x++)
{
for(int y = top; y < height; y++)
{
bmp.SetPixel(x,y,Color.Transparent);
}
}
Run Code Online (Sandbox Code Playgroud)
但这太慢了......与此相比,不安全的是什么?它会分配得更快吗?
最后我用PNG格式做了一个bmp.Save().
更新:
按照MusiGenesis的建议阅读http://www.bobpowell.net/lockingbits.htm后,我使用以下代码(适用于需要它的任何人)使其工作:
Bitmap bmp = new Bitmap(1000,1000,PixelFormat.Format32bppArgb);
BitmapData bmd = bmp.LockBits(new Rectangle(0, 0, bmp.Width,bmp.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
int PixelSize=4;
unsafe
{
for(int y=0; y<bmd.Height; y++)
{
byte* row=(byte *)bmd.Scan0+(y*bmd.Stride);
for(int x=0; x<bmd.Width; x++)
{ …Run Code Online (Sandbox Code Playgroud) 渲染框架时,我的C#应用程序中出现了意外的峰值。我在探查器中进行了遍历,发现以下内容:
在上面,增量时间为21毫秒(每秒60帧超过16.6毫秒),并在游戏中造成明显的停顿。甚至比这更糟,因为它仅在它之后才开始渲染(如您之后所看到的实心矩形),所以这21ms是一个谎言,根据该图,它更像是40ms,这太可怕了。
由于我不了解的原因,当打开vsync时,这种巨大差距永远不会发生。对于不熟悉vsync和游戏的用户,您不能在第一人称射击游戏中使用vsync,因为由于它的工作原理,它会削弱输入处理,因此我无法使用vsync,并且必须研究非vsync版本。我需要找到为什么非vsync版本具有这些主要停滞点的原因。
我的问题是,如何知道您从上面看到的图像中导致此延迟的原因?
性能分析器表示,这里有大量等待时间,超过80%的等待时间需要20%的CPU使用率(相比之下,准备渲染数据时需要100%的CPU使用率)。
探查器还显示该循环中没有运行任何渲染代码...这很奇怪,因为渲染器几乎完全控制了性能,因此,如果每秒不对帧进行任何上限,则应该使用纯蓝色淹没整个图形长方形。
问题在于,探查器显示的代码只是调用我在上面选择的区域中的轮询输入和dll:
请注意,的另一个调用DispatchRenderFrame是进行OpenGL调用,当我完全删除它时,它对程序没有影响,因此您可以忽略它。这可能意味着下面看到的用户输入也不会影响微笔画问题...但是我无法删除它,因为它是我用于窗口管理(OpenTK)的库的一部分。
我不确定CLR Worker线程是什么或正在做什么。它也发生在vsync一个(希望平滑分析一个)中,因此即使我不知道它是否是罪魁祸首,我猜也可能不是,但我不确定,因为它显示在“所需的vsync示例”也位于同一常规位置。
是否发生了一些中断,操作系统正在接管但未恢复我的线程,因为它被归类为CPU吞噬?只是一个想法...但是在示例中再次显示了蓝色条,因此我认为该Main线程实际上并未在我突出显示的内容中处于睡眠状态,并且实际上正在运行?
如您所见,我不确定突出显示的时间段是在告诉我什么,这是我需要帮助的地方。我不知道为什么此时代码中的等待百分比如此之高,或者从这里何处去进一步诊断问题。
编辑:我对Stopwatch类进行了一些粗略的剖析,以查看导致尖峰的位置,并且尖峰仅来自计算部分。OpenGL调用均不会导致任何延迟。它纯粹是在执行数学运算和访问数据的功能的函数内部发生的,或者写入预先分配的结构数组中。
额外说明:
这也让我好奇是否有办法让我强制使用,以使C#虚拟机获得尽可能多的CPU使用率?
没有产生垃圾。这不是 GC问题。我不能在申请期间运行GC,所以不会产生垃圾。渲染函数中的所有内容都是堆栈上的所有结构,唯一一次进入堆管理对象的是池化数组,其大小足以容纳所有渲染数据。它在探查器中出现的唯一时间是在开始和结束时,但是在渲染阶段不会运行。
假设我有
List<MyObject?> list = ...;
Run Code Online (Sandbox Code Playgroud)
我想把它变成List<MyObject>,但我无法删除可为空的引用。
下面是一个 MCVE。在我的项目中,我将可空引用警告转换为错误,因此下面注释掉的行将无法编译。
如果我这样做,.Where(e => e != null).Select(e => e!)那么在最新的 .NET Core 3.1.100 中就可以了,但是我无法将其提取到扩展方法中。
我尝试添加此扩展方法
public static IEnumerable<T> NotNull<T>(this IEnumerable<T> enumerable)
{
return enumerable.Where(e => e != null).Select(e => e!);
}
Run Code Online (Sandbox Code Playgroud)
但是它不会转换IEnumerable<MyObject?>为IEnumerable<MyObject>,我不确定为什么。这导致我出现如下错误:
[CS8619] 类型“列表”的值中引用类型的可空性与目标类型“列表”不匹配。
有没有办法让NotNull上面的功能以某种方式工作?
我正在研究继续使用 OpenGL 还是考虑使用 Vulkan 迁移来进行密集的瓶颈渲染对我来说是否更好。
但是,我不想在没有被告知的情况下进行跳跃。我一直在寻找 Vulkan 为我提供的好处,但是通过大量的谷歌搜索,我无法确切地找到可以提高性能的原因。人们会抛出诸如“OpenGL 慢,Vulkan 快得多!”之类的术语。或“低功耗!” 对这个话题不再多说。
因此,我很难评估我面临的问题是否是 Vulkan 可以帮助我解决的问题,或者我的问题是否是由于数量和计算造成的(在这种情况下,Vulkan 对我帮助不大) .
我假设 Vulkan 不会神奇地使管道中的事情变得更快(因为对于相同的缓冲区、制服和着色器,OpenGL 和 Vulkan 之间的三角形着色将大致相同)。我假设在 OpenGL 中导致悲伤的所有事情(例如:帧缓冲区和着色器程序更改)在任何一个 API 中都将同样痛苦。
我认为 Vulkan 提供了一些基于在线阅读无数内容的想法(我猜这肯定不是所有优点,或者这些是否属实):
没有[多?任何?] 绑定(或者更确切地说是“无绑定纹理”的更好版本),当我切换到无绑定纹理时我注意到我获得了显着的性能提升,但如果无绑定纹理有效,这甚至可能不值得作为一个点这样做,因此我不确定 Vulkan 是否在这里添加了任何内容
通过组合某种可以在 GPU 上执行而无需发送大量数据的命令列表来减少 CPU/GPU 通信
能够以 OpenGL 无法实现的多线程方式进行接口
但是,我不知道人们在现实世界中遇到哪些需要这些的情况,以及 OpenGL 如何限制这些情况。到目前为止,网上的所有例子都说“你可以跑得更快!” 但我还没有看到人们如何使用它来跑得更快。
我在哪里可以找到回答这个问题的信息?或者你知道一些具体的例子可以为我回答这个问题吗?也许更好的问题是人们在使用 OpenGL(或 D3D)时导致 Vulkan 成为一种东西的典型痛点在哪里?
一个不令人满意的答案的例子是这样的回应
您可以多线程并更快地向 Vulkan 提交内容。
但更令人满意的回应将类似于
在 Vulkan 中,您可以多线程处理您对 GPU 的提交。在 OpenGL 中,您不能这样做,因为您依靠实现来代表您进行适当的锁定和放置围栏,这可能最终会造成瓶颈。一个简单的例子是[这里的简短示例,OpenGL 没有针对情况 X 切断它],而在 Vulkan 中,它由 [动作 Y] 解决。
上面的最后一段可能并不准确,但我试图举例说明我要寻找的内容,而不会试图写出非常错误的东西。
我做需要连续数据的事情。现在使用 C# 10,我们可以执行public readonly record struct.
我喜欢记录所具有的自动 ToString 功能,所以为我完成这个功能真是太好了。
因此,以下等价吗?
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly struct MyVector
{
public readonly float X;
public readonly float Y;
public readonly float Z;
public MyVector(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
}
Run Code Online (Sandbox Code Playgroud)
与简洁的 C# 10 版本相比
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public readonly record struct MyVectorRecord(float X, float Y, float Z)
{
}
Run Code Online (Sandbox Code Playgroud)
或者我这样做会不小心踩到任何地雷吗?我的意思是,是否有任何事情在幕后进行,使得record我上面写的内容不能达到我想要的连续包装效果?我不能让记录插入填充、间距或做任何奇怪的事情。
我没有使用带有记录结构的向量类,而是将其用于说明目的。您可以忽略“浮点相等比较”之类的内容,因为我只关心是否可以将其传递给需要 X/Y/Z 连续序列的库。
我有一个选项,用户可以从FileChooser提交多个文件,以便由某些代码处理.结果将是用于读取文件的IO,然后是对存储数据的实际繁重计算.允许用户选择多个文件,并且由于文件处理不依赖于所选择的任何其他文件,因此使用线程更容易处理此问题.
此外,用户需要有一个按钮列表,每个要取消的任务一个,以及"全部取消"按钮.因此,我必须考虑选择性地或集体地杀死一个或所有任务的能力.
最后一个要求是我不会让用户通过打开大量文件来阻塞系统.因此,我想到了一个线程池数量有限的线程池(让我们假装我将它设置为4,任意数字).
我不确定如何正确地设置这一切.我有我需要做的逻辑,但使用正确的类是我被困的地方.
我已经检查了这个资源,所以如果答案是某种方式,那么我就误读了这篇文章.
是否有任何JavaFX类可以帮助我解决这种情况?
如果没有,我将如何将任务与某种线程池混合?我是否必须创建自己的线程池,或者是否已经为我提供了一个?
我是否在一个包含我愿意允许用户的最大线程数的单个地方?
我更喜欢使用已经在Java库中的一个,因为我不是多线程专家,并且担心我可能做错了.由于线程错误似乎是这个星球调试上最邪恶的东西,我想非常努力,以确保我这样做尽可能正确.
如果没有办法做到这一点,我必须推出自己的实现,那么最好的方法是做什么?
编辑:我应该注意,我通常是线程的新手,我之前使用过它们并且我正在阅读它们的书籍,但这将是我对它们的第一次主要用途,我真的很想做到这一点.
我正在使用 Spring,并且在终止时我让 @PreDestroy 清理 bean。我不明白为什么随机记录有时会成功,而在其他情况下会失败。
// Using Log4j2
Logger log = LogManager.getLogger(MyClass.class);
@PreDestroy
public void close() {
log.warn("Test");
}
Run Code Online (Sandbox Code Playgroud)
有时我什么也得不到(没有记录“测试”),有时我会得到:
[13:48:44] INFO MyClass: Test
Run Code Online (Sandbox Code Playgroud)
如果我包含System.out.println("Is this run?");在 close() 方法中,它将始终打印。
我实际上不确定发生了什么。我不知道是不是因为 JVM 正在关闭并且记录器被杀死......但我认为这会引发某种异常?
请注意,日志记录同时记录到文件 + 标准输出中,我不知道这是否会影响任何事情。日志记录适用于其他无数的数千行代码,但不是这个。
注意:如果它最终成为这个特定的库,我愿意切换日志库。
编辑: MyClass 将是 spring.xml 文档中的一个 bean。
我偶然发现了以下Code Review StackExchange并决定阅读它以供练习.在代码中,有以下内容:
注意:我不是在寻找代码审查,这只是链接代码的复制粘贴,因此您可以专注于手头的问题而不会干扰其他代码.我对实现'智能指针'不感兴趣,只是了解内存模型:
// Copied from the link provided (all inside a class)
unsigned int count;
mutex m_Mutx;
void deref()
{
m_Mutx.lock();
count--;
m_Mutx.unlock();
if (count == 0)
{
delete rawObj;
count = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
看到这一点让我立刻想到"如果两个线程何时进入count == 1并且两者都没有看到彼此的更新怎么办?最终可以看到count为零和双重删除?并且两个线程可能导致count变为-1然后删除从不发生?
互斥锁将确保一个线程进入临界区,但这是否保证所有线程都会正确更新?C++内存模型告诉我什么,所以我可以说这是一个竞争条件?
我查看了内存模型cppreference页面和std :: memory_order cppreference,但后一页似乎处理了一个原子参数.我找不到我想要的答案,或者我误解了它.任何人都可以告诉我,我所说的是错误还是正确,以及这段代码是否安全?
如果代码坏了则更正代码:
这是否正确的答案将计数变成原子成员?或者这是否有效并且在释放互斥锁上的锁之后,所有线程都看到了值?
如果这被认为是正确的答案,我也很好奇:
注意:我不是在寻找代码审查并试图查看这种解决方案是否能解决与C++内存模型相关的问题.
#include <atomic>
#include <mutex>
struct ClassNameHere {
int* rawObj;
std::atomic<unsigned int> count;
std::mutex mutex;
// ... …Run Code Online (Sandbox Code Playgroud) 我正在尽可能地复制Microsoft 网站示例中的所有内容,但没有生成任何内容。我创建了一个 MCVE 来尝试找出发生以下错误的原因:
Warning CS8034
Unable to load Analyzer assembly C:\Users\me\source\repos\SourceGenTest\SourceGenerators\bin\Debug\netstandard2.0\SourceGenerators.dll:
Could not find file 'C:\Users\me\source\repos\SourceGenTest\SourceGenerators\bin\Debug\netstandard2.0\SourceGenerators.dll'.
SourceGenLibrary 1 Active
Run Code Online (Sandbox Code Playgroud)
我已经检查了提供的路径,并且SourceGenerators.dll存在。这个错误对我来说毫无意义。
注意:在我提供的 MCVE 中,显然没有构建警告。不知道为什么,但源生成器仍然没有输出。
我的目标是拥有这样的工作流程:
SourceGenerators (class library)
is consumed by
SourceGenLibrary (class library)
is consumed by
SourceGenConsole (Console project)
Run Code Online (Sandbox Code Playgroud)
我希望分析器在类库中生成将在许多项目之间共享的定义。上述工作流程将其简化为一个依赖于一个库的项目,该库依赖于源生成器以尽可能保持 MCVE。
因为复制所有这些东西很烦人,如果你懒的话,这里有一个上传链接:下载链接 MCVE(据说发布后一周到期,但来源如下)。
相关信息:
$ dotnet --version
5.0.201
$ dotnet --list-sdks
5.0.103 [C:\Program Files\dotnet\sdk]
5.0.201 [C:\Program Files\dotnet\sdk]
Run Code Online (Sandbox Code Playgroud)
这些是源文件及其包含的内容。
/SourceGenTest.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 …Run Code Online (Sandbox Code Playgroud) 我有一些 SSBO 可以在着色器中访问。让我们说它是这样的
layout(std430, binding = 2) readonly buffer MyBuffer
{
int myData[];
};
Run Code Online (Sandbox Code Playgroud)
什么时候打电话比较合适glBindBufferBase?
现在我做类似的事情
glBindBuffer(GL_SHADER_STORAGE_BUFFER, name)
glBufferData(...)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, name)
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0)
Run Code Online (Sandbox Code Playgroud)
我不知道这是否会设置一些全局状态,从而为我绑定和取消绑定的每个着色器设置索引 2。
你能告诉我这个想法是否有任何缺陷:
Create, Bind SSBO, upload data, unbind for the SSBO
Bind shader
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, name)
Draw arrays
Unbind shader
Run Code Online (Sandbox Code Playgroud)
这是预期的使用方式吗?我只绑定一次SSBO,上传,然后就不再绑定了。这似乎有效,但我不知道它是否“正常工作”,因为我的 GPU 试图对我来说变得聪明,或者我是否违反了规范(我经历过但找不到这个问题的答案)。我曾经遇到过这样的情况:我做了一些可以在我的 GPU 上运行的事情,但在另一个 GPU 上却失败了,这让我对自己正在做的事情犹豫不决。
理想情况下,我希望进行一次函数调用,将 SSBO 交换到某种绑定中,然后进行绘制。我不确定是否可以在绑定着色器之前执行此操作,或者是否必须绑定着色器。如果有更好的方法来做到这一点,请建议。
简而言之,最终目标是在某些索引准备好用于上传数据后将某些 SSBO 绑定到某个索引上的最小方法。