Skip to content

Instantly share code, notes, and snippets.

@supermarin
Created February 3, 2020 14:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save supermarin/ea734b2c62f62651fe8aaa6b3e5f9e8b to your computer and use it in GitHub Desktop.
Save supermarin/ea734b2c62f62651fe8aaa6b3e5f9e8b to your computer and use it in GitHub Desktop.
Smallest reproduction of Combine's throttle() timing bug
// Bug initially observed when throttling a frequent signal out of a socket.
// When throttled to .seconds(1), there were around 50 ticks in a 60 second interval.
//
// This example eliminates the frequent source and just uses a 1-second timer,
// throttled by a 1-seconds throttle function.
//
// Expected behavior: 60 ticks in a minute
// Acutal behavior: ~33 ticks in a minute
import Combine
import Foundation
var subscription: AnyCancellable?
let publisher = PassthroughSubject<Date, Never>()
let t = Timer.publish(every: 1, on: RunLoop.main, in: .default).autoconnect()
subscription = t
.throttle(for: 1, scheduler: RunLoop.main, latest: true)
.measureInterval(using: RunLoop.main)
.sink { tick in
print("Tick (\(Date())): \(tick)")
}
// It doesn't really matter for this example if .throttle and .measureInterval are on a different scheduler.
//
// Output:
// Tick (2020-02-03 14:44:04 +0000): Stride(magnitude: 1.002100944519043)
// Tick (2020-02-03 14:44:06 +0000): Stride(magnitude: 1.9994419813156128)
// Tick (2020-02-03 14:44:08 +0000): Stride(magnitude: 1.9993900060653687)
// Tick (2020-02-03 14:44:09 +0000): Stride(magnitude: 1.0005799531936646)
// Tick (2020-02-03 14:44:11 +0000): Stride(magnitude: 2.0001190900802612)
// Tick (2020-02-03 14:44:13 +0000): Stride(magnitude: 2.000096917152405)
// Tick (2020-02-03 14:44:15 +0000): Stride(magnitude: 1.9999040365219116)
// Tick (2020-02-03 14:44:17 +0000): Stride(magnitude: 2.000032067298889)
// Tick (2020-02-03 14:44:19 +0000): Stride(magnitude: 1.9998869895935059)
// Tick (2020-02-03 14:44:20 +0000): Stride(magnitude: 1.0001459121704102)
// Tick (2020-02-03 14:44:22 +0000): Stride(magnitude: 2.0001250505447388)
// Tick (2020-02-03 14:44:24 +0000): Stride(magnitude: 1.9999510049819946)
// Tick (2020-02-03 14:44:26 +0000): Stride(magnitude: 1.9999810457229614)
// Tick (2020-02-03 14:44:28 +0000): Stride(magnitude: 1.9996320009231567)
// Tick (2020-02-03 14:44:29 +0000): Stride(magnitude: 1.0004398822784424)
// Tick (2020-02-03 14:44:31 +0000): Stride(magnitude: 1.9997590780258179)
// Tick (2020-02-03 14:44:32 +0000): Stride(magnitude: 1.0005919933319092)
// Tick (2020-02-03 14:44:34 +0000): Stride(magnitude: 1.9988949298858643)
// Tick (2020-02-03 14:44:35 +0000): Stride(magnitude: 1.000825047492981)
// Tick (2020-02-03 14:44:37 +0000): Stride(magnitude: 2.000025987625122)
// Tick (2020-02-03 14:44:39 +0000): Stride(magnitude: 2.0000590085983276)
// Tick (2020-02-03 14:44:41 +0000): Stride(magnitude: 2.000059962272644)
// Tick (2020-02-03 14:44:43 +0000): Stride(magnitude: 1.9998830556869507)
// Tick (2020-02-03 14:44:45 +0000): Stride(magnitude: 2.0001039505004883)
// Tick (2020-02-03 14:44:47 +0000): Stride(magnitude: 2.0001050233840942)
// Tick (2020-02-03 14:44:49 +0000): Stride(magnitude: 2.0000230073928833)
// Tick (2020-02-03 14:44:51 +0000): Stride(magnitude: 2.000051975250244)
// Tick (2020-02-03 14:44:53 +0000): Stride(magnitude: 2.0000020265579224)
// Tick (2020-02-03 14:44:55 +0000): Stride(magnitude: 2.0000070333480835)
// Tick (2020-02-03 14:44:57 +0000): Stride(magnitude: 2.0000460147857666)
// Tick (2020-02-03 14:44:59 +0000): Stride(magnitude: 1.9996339082717896)
// Tick (2020-02-03 14:45:01 +0000): Stride(magnitude: 2.0003610849380493)
// Tick (2020-02-03 14:45:03 +0000): Stride(magnitude: 1.999480962753296)
@supermarin
Copy link
Author

Here's a RxSwift version that behaves correctly:

    let pub = PublishSubject<Int>()
    let bag = DisposeBag()
    let t = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)

    t.throttle(.seconds(1), latest: true, scheduler: MainScheduler.instance)
    .subscribe({ _ in
        print("Tick \(Date())")
    })
    .disposed(by: bag)

Output

// Tick 2020-02-03 14:53:09 +0000
// Tick 2020-02-03 14:53:10 +0000
// Tick 2020-02-03 14:53:11 +0000
// Tick 2020-02-03 14:53:12 +0000
// Tick 2020-02-03 14:53:13 +0000
// Tick 2020-02-03 14:53:14 +0000
// Tick 2020-02-03 14:53:15 +0000
// Tick 2020-02-03 14:53:16 +0000
// Tick 2020-02-03 14:53:17 +0000
// Tick 2020-02-03 14:53:18 +0000
// Tick 2020-02-03 14:53:19 +0000
// Tick 2020-02-03 14:53:20 +0000
// Tick 2020-02-03 14:53:21 +0000
// Tick 2020-02-03 14:53:22 +0000
// Tick 2020-02-03 14:53:23 +0000
// Tick 2020-02-03 14:53:24 +0000
// Tick 2020-02-03 14:53:25 +0000
// Tick 2020-02-03 14:53:26 +0000
// Tick 2020-02-03 14:53:27 +0000
// Tick 2020-02-03 14:53:28 +0000
// Tick 2020-02-03 14:53:29 +0000
// Tick 2020-02-03 14:53:30 +0000
// Tick 2020-02-03 14:53:31 +0000
// Tick 2020-02-03 14:53:32 +0000
// Tick 2020-02-03 14:53:33 +0000
// Tick 2020-02-03 14:53:34 +0000
// Tick 2020-02-03 14:53:35 +0000
// Tick 2020-02-03 14:53:36 +0000
// Tick 2020-02-03 14:53:37 +0000
// Tick 2020-02-03 14:53:38 +0000
// Tick 2020-02-03 14:53:39 +0000
// Tick 2020-02-03 14:53:40 +0000
// Tick 2020-02-03 14:53:41 +0000
// Tick 2020-02-03 14:53:42 +0000
// Tick 2020-02-03 14:53:43 +0000
// Tick 2020-02-03 14:53:44 +0000
// Tick 2020-02-03 14:53:45 +0000
// Tick 2020-02-03 14:53:46 +0000
// Tick 2020-02-03 14:53:47 +0000
// Tick 2020-02-03 14:53:48 +0000
// Tick 2020-02-03 14:53:49 +0000
// Tick 2020-02-03 14:53:50 +0000
// Tick 2020-02-03 14:53:51 +0000
// Tick 2020-02-03 14:53:52 +0000
// Tick 2020-02-03 14:53:53 +0000
// Tick 2020-02-03 14:53:54 +0000
// Tick 2020-02-03 14:53:55 +0000
// Tick 2020-02-03 14:53:56 +0000
// Tick 2020-02-03 14:53:57 +0000
// Tick 2020-02-03 14:53:58 +0000
// Tick 2020-02-03 14:53:59 +0000
// Tick 2020-02-03 14:54:00 +0000
// Tick 2020-02-03 14:54:01 +0000
// Tick 2020-02-03 14:54:02 +0000
// Tick 2020-02-03 14:54:03 +0000
// Tick 2020-02-03 14:54:04 +0000
// Tick 2020-02-03 14:54:05 +0000
// Tick 2020-02-03 14:54:06 +0000
// Tick 2020-02-03 14:54:07 +0000
// Tick 2020-02-03 14:54:08 +0000
// Tick 2020-02-03 14:54:09 +0000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment