New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scheduler improvements #150
Conversation
@synchronized(scheduler) { | ||
NSAssert(scheduler.queue != NULL, @"+concurrentQueueScheduler used without being in a scheduler."); | ||
|
||
NSMutableArray *queue = (__bridge id)dispatch_get_specific(RACSchedulerImmediateSchedulerQueueKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dispatch_get_specific
/ dispatch_queue_set_specific
require a GCD dispatch queue, would -[NSThread threadDictionary]
work better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Coneko GCD queues aren't guaranteed to be pinned to a specific thread. It may change between the execution of blocks, so any thread-local storage is usually a bad idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the weird semantics of this scheduler is to guarantee that it never yields control while executing a scheduled block.
If it's called from a serial queue, if a block is currently executing it's going to be on the same thread. If it's called from a concurrent queue it's unpredictability doesn't change how you would treat a concurrent queue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Coneko Good point. @jspahrsummers 👍 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think what I said in https://github.com/github/ReactiveCocoa/issues/94#issuecomment-10820187 is going to be an issue. Maybe we should continue that discussion at the top level here.
@jspahrsummers Could you expand on that a bit more? |
Well, for instance, I was very close to implementing I imagine that similar patterns are common in RAC consumers, and, with this implementation, any
|
@jspahrsummers I'm not sure I follow. This proposed implementation doesn't support |
Sorry, I mean a |
Ah yeah, but I think that's ok-ish. We have to make the strong claim that schedulers are only valid when used with schedulers. They break as soon as you intermingle them with GCD or Maybe that's too inflexible, but I'd be curious to hear a case where it would be. |
Maybe we should back up a little bit. Why does |
|
||
// These properties should only be accessed while synchronized on self. | ||
@property (nonatomic, readonly, strong) NSMutableArray *disposables; | ||
@property (nonatomic, assign) BOOL disposed; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should have a getter = isDisposed
.
|
||
// A scheduler that executes blocks in the current scheduler, after any blocks | ||
// already scheduled have completed. If the current scheduler cannot be | ||
// determined, it uses the main queue scheduler. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*+mainThreadScheduler
- (void)schedule:(void (^)(void))block { | ||
NSParameterAssert(block != NULL); | ||
|
||
NSMutableArray *queue = NSThread.currentThread.threadDictionary[RACIterativeSchedulerQueue]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why wouldn't we use a serial GCD queue + queue-specific data to represent this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't manually run a GCD queue, so we can't guarantee when the enqueued blocks are executed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which part of the interface is that guaranteeing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 I'll clarify the docs that they'll be called immediately after the current block.
return [RACScheduler schedulerWithScheduleBlock:^(void (^block)(void)) { | ||
[queue addOperationWithBlock:block]; | ||
}]; | ||
+ (BOOL)onMainThread { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about +isOnMainThread
?
✒️ 🙏 |
|
||
[NSThread.currentThread.threadDictionary removeObjectForKey:RACIterativeSchedulerQueue]; | ||
} else { | ||
[queue addObject:block]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block should be manually copied.
Sorry, one additional note about block management. |
✊ |
Add support for Xcode 8 and Swift 2.3
A start on solving #94, #136.
Alright so here's an attempt at fleshing out
RACScheduler
.It does a couple things:
+currentScheduler
.My current thinking is that all subscriptions would use the
+subscriptionScheduler
so that we can ensure that by the time we're in adidSubscribe
block, we can determine the+currentScheduler
.This would enable us to fix #94 by deferring the re-subscription on the current scheduler.
It supports #136 by making concurrency explicit with the option of creating a serialized scheduler from a concurrent scheduler.
So where are the holes in this? Does this really address the problems? What sorts of crazy edge cases do we need to test?