On Sep 4, 2019, at 19:52, Bar Harel <bzvi7...@gmail.com> wrote: > > I'm sorry but I truly fail to see the complication: > > sem = Semaphore(10) # line num 1 somewhere near executor creation > sem.acquire() # line number 2, right before submit > future = executor.sumbit(...) > future.add_done_callback(lambda x: sem.release()) # line number 3, right > after submit. > > It's only 3 lines of code, barely noticeable,
Can you really barely notice the difference between this: future = x.submit(func, arg) … and this: sem.acquire() future = x.submit(func, arg) future.add_done_callback(lambda x: sem.release()) You’ve turned 1 line of code into 3, and the number of characters or tokens or concepts to think about have all increased even more; the actual function is now buried among the boilerplate. I can’t see how you can call that “barely noticeable”. There’s also the fact that you have to learn about semaphores to do it this way. To you or me that may seem trivial, but one of the appeals of concurrent.futures is that you don’t have to think about synchronization, because it’s all tied up in the queue, which means it can even be used by rank novices who don’t even know the difference between a condition variable and a barrier. (I’m not saying people shouldn’t learn how to use semaphores. They should also learn how to build their own thread pools, and understand how futures work under the covers, and so on, but the fact that they can make their code concurrent, and do it correctly, even before they’ve learned all that is pretty nice, and I think this proposal is a simple extension that extends that niceness.) I have taught novices how to use executors in a few minutes. Often they just need to look at the parallel-downloader example and they get it. And I’m pretty sure I could also explain to them how and why to limit concurrency by passing a max_queue_len parameter in a few minutes. In fact, I’ve seen a novice find the equivalent feature in Ruby in a couple minutes of web searching and add it to his program, only stumbling over trying to figure out the deal with all the different fail policies (IIRC, Ruby has all the options from Java and more—block, raise, discard and return an empty future, run synchronously in your thread, pass the method to an arbitrary fail function… I think either of the first two would satisfy 90% of the uses, so that complexity isn’t needed. At least if nobody’s asked for it.) > quite clear, with minimal overhead. But the max_queue_len is even clearer, and has even less overhead (on top of a whole lot less boilerplate). > Just think the general idea might be a premature optimisation. It’s not about optimization—as I already said in my previous email (the one you seem to be replying to, although it’s not the one you quoted); the performance difference is unlikely to matter in most code. It’s about readability, boilerplate, novice-friendliness, etc. These are much bigger wins than saving a microsecond in a process that’s slow enough to execute on another thread. All that being said, despite it making no difference in the vast majority of real-world uses, it still seems a little perverse to insist on using the slower code here. I will gladly write slower code where it doesn’t matter if it makes it easier for more people to understand my code, but I rarely write slower code because of some matter of abstract principle, and especially not if it makes it harder for more people to understand my code. > If already, I would have either changed the signature of the executor > creation to have a new 'max_queue' keyword-only argument, or allow you to > enter the queue as an input, If you would have added it in the original version, how is adding it now any different? I assume the only reason you would have added it is that it’s a nicer API. So what counters that in the opposite direction? It’s not like it’s going to cause any backward compatibility issues or anything, is it? > but I still believe that any attempt to create such an interface will just > cause more complications than the simple 3 line solution. Why would it cause complications? It’s dead simple to design and implement, dead simple to understand, and relies on well-understood and well-rested behavior that’s been part of the queue and mp modules since long before concurrent even existed. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/BBSEGWPNCHL3GRL5VRRQSEQM3VJLPGE5/ Code of Conduct: http://python.org/psf/codeofconduct/