Sprite Kit 中可重用的多线程实现 [英] reusable multithread implementation in Sprite Kit

查看:26
本文介绍了Sprite Kit 中可重用的多线程实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一款 Sprite Kit 游戏,我需要进行一些多线程处理以保持健康的 fps.

I am working on a Sprite Kit game and I need to do some multithreading to maintain the healthy fps.

更新时我调用一个函数来创建大量 UIBezierPaths 并使用 C++ 静态库合并它们.

On update I call a function to create a lot of UIBezierPaths and merge them using a C++ static library.

如果我有超过 10 个形状,帧速率会急剧下降,所以我决定尝试 GCD 并尝试使用单独的线程解决问题.

If I have more than 10 shapes the frame rate drops dramatically so I decided I give GCD a try and try to solve the issue with a separate thread.

我把它放在 didMoveToView 中:

I put this in didMoveToView:

queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

在每帧调用的函数中,我称之为:

and in the function that is being called on every frame, I call this:

dispatch_async(queue,^(void){[self heavyCalculationsFunc];});

对于熟悉 GCD 的人来说,很明显它会在每一帧上创建一个新线程,但对我来说还不清楚.

For somebody who knows GCD well it might be obvious it creates a new thread on every frame, but for me it wasn't clear yet.

我的问题是,有没有办法重用我想在更新时调用的线程?

My question is, is there any way to re-use a thread that I want to call on update?

提前感谢您的帮助!

推荐答案

如果您需要在每一帧上完成工作,并且需要在渲染帧之前完成,那么多线程可能对您没有帮助,除非你愿意为此付出很多努力.

If you have work that you need to do on every frame, and that needs to get done before the frame is rendered, multithreading probably won't help you, unless you're willing to put a lot of effort into it.

保持帧速率完全取决于时间——不是 CPU 资源,只是时间.要保持 60fps 的帧率,您有 16.67 毫秒的时间来完成所有工作.(实际上,少于这个时间,因为 SpriteKit 和 OpenGL 需要一些时间来渲染您的工作结果.)这是一个同步问题 - 你有工作,你有特定的时间去做,所以提高绩效的第一步是减少工作或提高效率.

Maintaining a frame rate is all about time — not CPU resources, just wall time. To keep a 60fps framerate, you have 16.67 ms to do all your work in. (Actually, less than that, because SpriteKit and OpenGL need some of that time to render the results of your work.) This is a synchronous problem — you have work, you have a specific amount of time to do it in, so the first step to improving performance is to do less work or do it more efficiently.

另一方面,多线程通常用于处理异步问题 — 您需要做一些工作,但不需要立即完成,因此您可以继续处理其他问题你现在需要做的事情(比如在 16 毫秒内从你的更新方法返回以保持你的帧速率)并稍后检查该工作的结果(比如,在稍后的帧上).

Multithreading, on the other hand, is generally for asynchronous problems — there's work you need to do, but it doesn't need to get done right now, so you can get on with the other things you need to do right now (like returning from your update method within 16 ms to keep your framerate up) and check back for the results of that work later (say, on a later frame).

不过,这两个定义之间有一点回旋的余地:几乎所有现代 iOS 设备都有多核 CPU,所以如果你正确地玩你的牌,你可以在同步问题中加入一点异步性 并行化您的工作量.完成这项工作并把它做好是不小的壮举——它一直是 的主题大型游戏工作室多年来的认真研究和投资.

There is a little bit of wiggle room between these two definitions, though: just about all modern iOS devices have multicore CPUs, so if you play your cards right you can fit a little bit of asynchronicity into your synchronous problem by parallelizing your workload. Getting this done, and doing it well, is no small feat — it's been the subject of serious research and investment by big game studios for years.

看看场景如何处理动画帧" 在 SpriteKit 编程指南中.那是你的 16 毫秒时钟.浅蓝色区域是 Apple 的 SpriteKit(以及 OpenGL 和其他系统框架)代码负责的 16 毫秒的片段.其他切片是你的.让我们展开该图以更好地查看:

Take a look at the figure under "How a Scene Processes Frames of Animation" in the SpriteKit Programming Guide. That's your 16 ms clock. The light blue regions are slices of that 16 ms that Apple's SpriteKit (and OpenGL, and other system frameworks) code is responsible for. The other slices are yours. Let's unroll that diagram for a better look:

如果你在这些切片中做太多工作,或者让 SpriteKit 的工作负载过大,整个事情会变得超过 16 毫秒,并且你的帧率会下降.

If you do too much work in any of those slices, or make SpriteKit's workload too large, the whole thing gets bigger than 16 ms and your framerate drops.

线程化的机会是在同一时间线上在另一个 CPU 上完成一些工作.如果 SpriteKit 对动作、物理和约束的处理不依赖于该工作,您可以与这些事情并行进行:

The opportunity for threading is to get some work done on the other CPU during that same timeline. If SpriteKit's handling of actions, physics, and constraints doesn't depend on that work, you can do it in parallel with those things:

或者,如果您的工作需要在 SpriteKit 运行动作和物理,但是您需要在 update 方法中完成其他工作,您可以在完成 update 工作的其余部分时将一些工作发送到另一个线程,然后在您的 update 方法中检查结果:

Or, if your work needs to happen before SpriteKit runs actions & physics, but you have other work you need to do in the update method, you can send some of the work off to another thread while doing the rest of your update work, then check for results while still in your update method:

那么如何完成这些事情呢?这是使用调度组的一种方法,并假设动作/物理/约束不依赖于您的背景工作——这完全不在我的脑海中,所以它可能不是最好的.:)

So how to accomplish these things? Here's one approach using dispatch groups and the assumption that actions/physics/constraints don't depend on your background work — it's totally off the top of my head, so it may not be the best. :)

// in setup
dispatch_queue_t workQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t resultCatchingGroup = dispatch_group_create();
id stuffThatGetsMadeInTheBackground;

- (void)update:(NSTimeInterval)currentTime {
    dispatch_group_async(group, queue, ^{
        // Do the background work 
        stuffThatGetsMadeInTheBackground = // ...
    });
    // Do anything else you need to before actions/physics/constraints
}

- (void)didFinishUpdate {
    // wait for results from the background work
    dispatch_group_wait(resultCatchingGroup, DISPATCH_TIME_FOREVER);

    // use those results
    [self doSomethingWith:stuffThatGetsMadeInTheBackground];
}

当然,dispatch_group_wait 顾名思义,会阻塞执行以等待后台工作完成,因此您仍然有 16 毫秒的时间限制.如果前台工作(您的 update 的其余部分,加上 SpriteKit 的动作/物理/约束工作以及您为响应这些事情而完成的任何其他工作)在您的后台工作之前完成,您会等的.如果后台工作加上 SpriteKit 的渲染工作(加上你在生成后台工作之前在 update 中所做的任何事情)花费的时间超过 16 毫秒,你仍然会丢帧.因此,诀窍是充分了解您的工作量,以便妥善安排它.

Of course, dispatch_group_wait will, as its name suggests, block execution to wait until your background work is done, so you still have that 16ms time constraint. If the foreground work (the rest of your update, plus SpriteKit's actions/physics/constraints work and any of your other work that gets done in response to those things) gets done before your background work does, you'll be waiting for it. And if the background work plus SpriteKit's rendering work (plus whatever you do in update before spawning the background work) takes longer than 16 ms, you'll still drop frames. So the trick to this is knowing your workload in enough detail to schedule it well.

这篇关于Sprite Kit 中可重用的多线程实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆