Ios 如何在Objective-C中限制CoreMIDI

Ios 如何在Objective-C中限制CoreMIDI,ios,multithreading,Ios,Multithreading,我在iOS上的CoreMIDI连接显然足够快,可以处理任何碰到它的东西。。。如果我只是做一些简单的对象创建和NSLog。在UI中,我没有时间处理所有输入的内容。UI可能会崩溃,或者只是完成处理太晚 然而,我需要对CoreMIDI输入进行真正的处理和UI显示。我希望每隔1毫秒或2毫秒处理最新的消息。我一直在使用一个每隔1ms由计时器触发的方法清空的集合(processFromServerAsync)。一个问题是,如果我抓住并替换以下信息,我认为有些信息可能会从裂缝中掉落: NSDictionary

我在iOS上的CoreMIDI连接显然足够快,可以处理任何碰到它的东西。。。如果我只是做一些简单的对象创建和
NSLog
。在UI中,我没有时间处理所有输入的内容。UI可能会崩溃,或者只是完成处理太晚

然而,我需要对CoreMIDI输入进行真正的处理和UI显示。我希望每隔1毫秒或2毫秒处理最新的消息。我一直在使用一个每隔1ms由计时器触发的方法清空的集合(
processFromServerAsync
)。一个问题是,如果我抓住并替换以下信息,我认为有些信息可能会从裂缝中掉落:

NSDictionary *queueCopy = [self.queue copy];
// here the dictionary could get messages not in the queue copy!
self.queue = [NSMutableDictionary dictionary];
我意识到我可以通过与锁同步来处理此问题,锁很容易出错:

-(NSMutableDictionary *)messageQueue {
    @synchronized(self) {
        if (!messageQueue_)
            self.messageQueue = [NSMutableDictionary dictionary];
        return messageQueue_;
    }
}

-(NSDictionary*)clearMessageQueueAndReturnCopy {
    @synchronized(self) {
        if (!messageQueue_)
            return [NSDictionary dictionary];
        NSDictionary *retVal = [messageQueue_ copy];
        self.messageQueue = [NSMutableDictionary dictionary];
        return retVal;
    }
}

然而,我甚至不相信我以正确的方式处理了这个问题。节流通常是如何进行的(即使在Obj-C之外)?我肯定无法处理UI或程序中的所有消息。

有一些成熟的模式用于节流传入数据流。这在金融业中经常出现,在金融业中,你可能有一个每秒向系统发送10万条消息的数据源

您使用滑动窗口机制来丢弃冗余消息,同时确保客户端拥有数据的最新副本。在一段时间内(几毫秒)设置窗口,然后为每个数据流设置队列(表示特定的CC、midi音符等)。当第一条消息传入时,启动全局计时器。您可以立即将该消息发送给客户端。如果在窗口期间有任何其他东西进来,请将其推到队列中。队列只有一个条目—最新的值—因此每次后续更新都会覆盖排队的值。当计时器滴答作响(窗口结束)时,您将向客户端发送最新消息。然后,您在收到下一条消息后立即将其发送出去,启动一个新窗口并重复。这在淹没客户端和避免计时器窗口的更新间隔出现别名之间提供了合理的平衡。在1-2毫秒的时间间隔内,别名问题较少,因此更粗糙的刚性计时器方法可能适合您


关键是确保每个数据流都有单独的窗口。您不能因为控件发生更改而冒着覆盖或忽略(比如)注释的风险。一个计时器,每个Midi消息编号一个单条目队列。

有一些成熟的模式用于限制传入数据流。这在金融业中经常出现,在金融业中,你可能有一个每秒向系统发送10万条消息的数据源

您使用滑动窗口机制来丢弃冗余消息,同时确保客户端拥有数据的最新副本。在一段时间内(几毫秒)设置窗口,然后为每个数据流设置队列(表示特定的CC、midi音符等)。当第一条消息传入时,启动全局计时器。您可以立即将该消息发送给客户端。如果在窗口期间有任何其他东西进来,请将其推到队列中。队列只有一个条目—最新的值—因此每次后续更新都会覆盖排队的值。当计时器滴答作响(窗口结束)时,您将向客户端发送最新消息。然后,您在收到下一条消息后立即将其发送出去,启动一个新窗口并重复。这在淹没客户端和避免计时器窗口的更新间隔出现别名之间提供了合理的平衡。在1-2毫秒的时间间隔内,别名问题较少,因此更粗糙的刚性计时器方法可能适合您


关键是确保每个数据流都有单独的窗口。您不能因为控件发生更改而冒着覆盖或忽略(比如)注释的风险。一个计时器,每个Midi消息编号一个单条目队列。

@TimKemp如果您在外部Midi硬件上以最快的速度滑动四个滑块,这对CoreMIDI来说不算太多,但要做任何逻辑处理都很困难。要做好准备。好的,我给你准备了,这是很多数据。@TimKemp如果你在外部MIDI硬件上以最快的速度滑动四个滑块,这对CoreMIDI来说不算太多,但要做任何逻辑处理都很困难。我已经准备好了。好的,我知道了,这是很多数据。例如,在金融示例中,每个股票符号有一个数据流?你运行的计时器和数据流一样多?另外,现在我担心我的处理无法在分配的时间内完成。。。我想我只有在处理完之后才需要重新安排时间来处理这个问题……实际上每个符号每个属性都有一个流,例如沃达丰出价,沃达丰出价是两个流。不过,在屏幕上经常会出现合并,因此您使用的窗口为250-500毫秒。我编辑了答案,因为不清楚您是否只使用了一个共享计时器。“流”更像是单条目队列,您只保留该特定数据的最新副本。。。这里的窗口大小要小得多,处理时间可能会超过窗口大小,所以。。。什么,忘记窗口并尽快重新安排?如果处理时间超过窗口大小,则限制窗口大小太小。话虽如此,如果您只是在更新GUI,那么您无论如何只能大约每16毫秒更新一次(每秒60帧)。一个更简单的方案是将每个MIDI消息编号的最新值保留在内存中,然后每隔$window秒自动将其发布到消费者端一次并清除它。在消息编号和控制更改编号上键入的关联数组将完成存储部分,然后您有一个计时器来刷新它。祝你好运。您可能会发现,您只需要调节显示部分。例如,在财务示例中,每个股票符号有一个数据流?你运行的计时器和数据流一样多?另外,现在我担心我的处理无法在分配的时间内完成。。。我猜