uni-app点击回到顶部_回到基础-每个人都记得我们停在哪里(那个记忆)!

uni-app点击回到顶部

uni-app点击回到顶部

I added a new feature to BabySmash during lunch, so that if your (baby's) mouse wheel is over a shape and they scroll the wheel, the system will play a sound and zoom that object in or out. The mouse wheel events come REALLY fast, as do most mouse events.

我在午餐时为BabySmash添加了一个新功能,这样,如果您(婴儿的)鼠标滚轮在某个形状上并且他们滚动滚轮,系统将播放声音并放大或缩小该对象。 鼠标滚轮事件的发生速度非常快,大多数鼠标事件也是如此。

The general idea is this. I've got the PInvoke/DllImport call to the PlaySound API and a couple of helper methods. If the WAV wasn't cached, I'd go get it and store it away. All this code was kind of written on auto-pilot, you know? It's called very quickly in the MouseWheel event and works fine...until it totally doesn't work at all.

总体思路是这样的。 我有对PlaySound API的PInvoke / DllImport调用和一些辅助方法。 如果没有缓存WAV,我将其保存起来。 所有这些代码都是通过自动驾驶编写的,您知道吗? 在MouseWheel事件中调用它非常快,并且效果很好...直到完全不起作用为止。

I found that when I wheeled the mouse REALLY fast, sometimes it'd get a nasty burst of loud static instead of the nice WAV file playing as I expected.

我发现,当我真正快速移动鼠标时,有时会发出讨厌的一阵大声的静态声音,而不是像预期的那样播放漂亮的WAV文件。

I store my WAV files inside the resources of BabySmash.exe (for now) so I just hold them in memory. Initially I would pull them out of the resource every time, but then I added some basic caching. (I probably should have used Chad and Jeremy's cache, but anyway)

我将WAV文件存储BabySmash.exe的资源中(目前),因此我只是将它们保存在内存中。 最初,我每次都会将它们从资源中拉出,但是后来我添加了一些基本的缓存。 (我可能应该使用乍得杰里米的缓存,但是无论如何)

[DllImport("winmm.dll")]
public static extern bool PlaySound(byte[] data, IntPtr hMod, UInt32 dwFlags);

public static void PlayWavResource(string wav)
{
byte[] b = GetWavResource(wav);
PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY);
}

public static void PlayWavResourceYield(string wav)
{
byte[] b = GetWavResource(wav);
PlaySound(b, IntPtr.Zero, SND_ASYNC | SND_MEMORY | SND_NOSTOP);
}

private static byte[] GetWavResource(string wav)
{
//TODO: Is this valid double-check caching?
byte[] b = null;
if (cachedWavs.ContainsKey(wav))
b = cachedWavs[wav];
if (b == null)
{
lock (cachedWavsLock)
{
// get the namespace
string strNameSpace = Assembly.GetExecutingAssembly().GetName().Name;

// get the resource into a stream
using (Stream str = Assembly.GetExecutingAssembly().GetManifestResourceStream(strNameSpace + wav))
{
if (str == null)
throw new ArgumentException(wav + " not found!");
// bring stream into a byte array
var bStr = new Byte[str.Length];
str.Read(bStr, 0, (int)str.Length);
cachedWavs.Add(wav, bStr);
return bStr;
}
}
}
return b;
}

Anyway, I kind of forgot that byte was a value type and in a chat this afternoon Larry made this comment. You might remember that the man responsible for the PlaySound() API is none other than Larry Osterman, who I interviewed last year. Here's our chat transcript:

无论如何,我有点忘记了字节是一个值类型,今天下午在聊天中Larry发表了此评论。 您可能还记得,负责PlaySound() API的人就是我去年采访过的拉里·奥斯特曼( Larry Osterman) 。 这是我们的聊天记录:

Larry Osterman‎‎:My guess is that you're deleting the array b before the PlaySound has completed. or rather the CLR is.

拉里·奥斯特曼(Larry Osterman) 我的猜测是您要在PlaySound完成之前删除数组b。 或者更确切地说是CLR。

‎‎Scott Hanselman:even though it's on the stack?ahI get itthe GC is getting to it

斯科特·汉瑟曼(Scott Hanselman): 即使它在堆栈上? 我知道了GC正在达到目标

‎‎Larry Osterman‎‎:when you say snd_async, it queues the actual playsound operation to a worker thread.Yup, GC makes it go away.

拉里·奥斯特曼当您说snd_async时,它将实际的playsound操作排队到工作线程中。 是的,GC使它消失了。

When I started going really fast with dozens of calls to PlaySound() a second, I was piling these up and eventually hit the point where one byte[] that was being played would disappear (get garbage collected) and I'd hear the sound of zeros being played. Which sounds much like static. (kidding) ;) I could have made the sound play synchronously, but that doesn't fit well with BabySmash's free-form maniacal button pressing.

当我开始每秒快速调用几十个PlaySound()时,我很快就将这些堆积起来,并最终碰到正在播放的一个byte []会消失(收集垃圾)并听到声音的点。的零。 听起来很像静态。 (设置);)我可以使声音同步播放,但这与BabySmash的自由形式狂热按钮按下效果不佳。

Larry suggested I copy the WAV files to a temporary location so they'd be "pinned" down, as there wasn't really a good way to pin these in memory that either of us could come up with. Here's what I did. I grabbed a TempFileName, put the WAV files on disk there and switched the call to PlaySound to the filename overloaded version, rather than the byte[] version. I use TempFileCollection which is helpful because it automatically tries to delete the temporary files when its finalizer runs.

Larry建议我将WAV文件复制到一个临时位置,以便将它们“固定”下来,因为实际上并没有一种很好的方法将这些文件固定在我们两个人都可以想到的内存中。 这就是我所做的。 我抓起一个TempFileName,将WAV文件放在磁盘上,并将对PlaySound的调用切换到文件名重载版本,而不是byte []版本。 我使用TempFileCollection很有帮助,因为它在终结器运行时会自动尝试删除临时文件。

[DllImport("winmm.dll", SetLastError = true)]
static extern bool PlaySound(string pszSound, IntPtr hmod, UInt32 fdwSound);

public void PlayWavResource(string wav)
{
string s = GetWavResource(wav);
PlaySound(s, IntPtr.Zero, SND_ASYNC);
}

public void PlayWavResourceYield(string wav)
{
string s = GetWavResource(wav);
PlaySound(s, IntPtr.Zero, SND_ASYNC | SND_NOSTOP);
}

TempFileCollection tempFiles = new TempFileCollection();

private string GetWavResource(string wav)
{
//TODO: Is this valid double-check caching?
string retVal = null;
if (cachedWavs.ContainsKey(wav))
retVal = cachedWavs[wav];
if (retVal == null)
{
lock (cachedWavsLock)
{
// get the namespace
string strNameSpace = Assembly.GetExecutingAssembly().GetName().Name;

// get the resource into a stream
using (Stream str = Assembly.GetExecutingAssembly().GetManifestResourceStream(strNameSpace + wav))
{
string tempfile = System.IO.Path.GetTempFileName();
tempFiles.AddFile(tempfile,false);
var bStr = new Byte[str.Length];
str.Read(bStr, 0, (int)str.Length);
File.WriteAllBytes(tempfile, bStr);
cachedWavs.Add(wav, tempfile);
return tempfile;
}
}
}
return retVal;
}

It's coarse, but it works, and now I can move on to some cleanup with this bug behind me. The Back to Basics lesson for me is:

这很粗糙,但是可以用,现在我可以继续进行一些清理工作,以解决这个问题。 对我来说,回到基础课是:

  • Don't forget there is a Garbage Collector out there, doing just that.

    不要忘了那里有一个垃圾收集器。

    • It's easy to forget all about it, but it's so important to know who has a finger on your memory when you're moving back and forth over the unmanaged/managed boundary.

      忘记所有这些很容易,但是当您在非托管/托管边界上来回移动时,知道谁在您的记忆中非常重要。
  • Edge cases are no fun.

    边缘情况不好玩。

    • There are always edge cases, race conditions and deadlocks to be found, and I'm sure I've got more left to find! (notice my lack of surety around the lock() call in the comments?)

      总会发现一些极端情况,比赛条件和僵局,我敢肯定,还有更多可以发现的地方! (注意到我在注释中的lock()调用周围缺乏保证吗?)
    • Know your patterns for best practices or, better yet, know where to go to find the answers.

      了解最佳实践的模式,或者更好的是,知道在哪里找到答案。
  • Your software typically runs exactly as you wrote it.

    您的软件通常完全按照您编写的方式运行。

    • Even though this was a GC doing something I didn't expect, it was doing its job with the code I provided it. Given how I was using the byte array, it's very deterministic in its behavior.

      即使这是GC所做的我没想到的事情,它也正在使用我提供的代码来完成它的工作。 鉴于我使用字节数组的方式,它的行为非常确定。
  • Know what's going wrong before you try to fix it.

    在尝试解决问题之前,请先了解问题所在。

    • Once I understood the bug, I was able to reproduce the bug much more easily. "Flakies" are scary, but Bugs are just bugs. If I tried to fix it without understanding it, I'd just be programming by coincidence. (And I may still be! That's the rub.)

      一旦理解了该错误,便能够更轻松地重现该错误。 “ Flakies”很可怕,但是Bug只是bug。 如果我试图在不了解的情况下进行修复,那我只是巧合而已。 (而且我可能仍然会!就是这样。)

Have a nice day!

祝你今天愉快!

翻译自: https://www.hanselman.com/blog/back-to-basics-everyone-remember-where-we-parked-that-memory

uni-app点击回到顶部

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值