[swift-corelibs-dev] libdispatch roadmap and api addition proposal
Joakim Hassila
Joakim.Hassila at orc-group.com
Thu Dec 10 03:06:27 CST 2015
> On 8 dec. 2015, at 17:07, Pierre Habouzit <phabouzit at apple.com> wrote:
>
> My point is, adding API to dispatch is not something we do lightly. I’m not keen on an interface that only works for base queues. Mac OS and iOS code where dispatchy code is pervasive, more than 2 queue deep queues hierarchy is very common typically.
Gotcha.
>
>>
>> That would indeed be a very interesting idea, the problem is that the thread using ‘dispatch_barrier_trysync’ is not returning to the pthread_workqueue pool to grab the next dispatch queue for processing, but is instead going back to block on a syscall (e.g. read() from a socket) - and even the latency to wake up a thread (as is commonly done now) with mutex/condition signaling is way too slow for the use case we have (thus the very ugly workaround with a spin thread for some deployments).
>> <snip>
>> Perhaps we have to live with the limited implementation we have for practical purposes, but I have the feeling that the behavior we are after would be useful for other use cases, perhaps the queue attribute suggested above could be another way of expressing it without introducing new dispatch API.
>
> I completely agree with you, but I think that the way to address this is by making the thread pool smarter, not having the developper have to sprinkle his code with dispatch_barrier_trysync() where he feels like it. Using it properly require a deep understanding of the implementation of dispatch he’s using and changes on each platform / version combination. that’s not really the kind of interface we want to build.
>
> “overcommit” is exactly the hint you’re after as far as the queue is concerned. It means “if I’m woken up, bring up a new thread provided it doesn’t blow up the system, no matter what”. So make your queue non overcommit by targetting it manually to dispatch_get_global_queue(0, 0) (that one isn’t overcommit), and make the thread pool smarter. That’s the right way to go and the design-compatible way to do it.
Ok, this is interesting (and probably just points out my misunderstanding of the intended semantics of the overcommit flag) - the part with “doesn’t blow up the system” is actually not clear from the header files, it says:
++++++
* @constant DISPATCH_QUEUE_OVERCOMMIT
* The queue will create a new thread for invoking blocks, regardless of how
* busy the computer is.
++++++
The ‘regardless of how busy the computer is’ was also the implementation of overcommit queues in pwq, so we essentially banned the usage of them here internally as the semantics where not very usable for us, as a new thread was always created (and we do use a fairly large number of dispatch queues).
If we would have semantics like:
“overcommit” - "if I’m woken up, bring up a new thread provided it doesn’t blow up the system, no matter what” and the definition of “blowing up the system” is to not have more concurrent running threads than there are active cores
“non overcommit” - “only bring up a new thread a provided that enough ‘pressure’ is applied” (to allow for essentially the ping pong you suggest)
Then I think we can work with making the thread pool smarter and get desired behavior - will think a bit more about it (I think that some care would be required to not have essentially lost wakeups for the non overcommit variant in that case), but it feels like a possibly better way forward, thanks.
Would such interpretation of the overcommit attribute semantics be reasonable? (we wouldn’t want to have a completely different view of it to keep the API behavior robust across platforms)
> If your thread block in read() then I would argue that it should use a READ dispatch source instead, that way, the source would get enqueued *after* your async and you can ping pong. Doing blocking read()s is not dispatchy at all and will cause you all sorts of problems like that one, because re-async doesn’t work for you.
Here we are a bit living with legacy considerations, but perhaps one possible way we are discussing is if such threads could use the pwq API (at the tail end) to facilitate the behavior you suggest.
I.e. pseudocode:
f() // legacy non-dispatchy code
{
read() // get some new work
dispatch_async() // dispatch the work on a non-overcommit queue
pthread_workqueue_additem_np(q, f, ...) // repeat f(), switch between overcommit/nonovercommit target work queues as needed/desired, this thread could thus be stolen to process the above dispatch_async
}
Thanks!
Joakim
________________________________
This e-mail is confidential and may contain legally privileged information. It is intended only for the addressees. If you have received this e-mail in error, kindly notify us immediately by telephone or e-mail and delete the message from your system.
More information about the swift-corelibs-dev
mailing list