Hello,

Can you check the condition inside the lock? The following pattern seems 
simpler to me:

def _populate(self):
    with self._lock:
        if self._populated:
            return
        # … populate …
        self._populated = True

You can look at Apps.populate for an example of this pattern.

Please forgive me if I missed a reason for using something more complicated.

self._lock needs to be a RLock if _populate can call itself recursively in a 
given thread.

Best regards,

-- 
Aymeric.

> On 12 Jul 2016, at 03:20, Cristiano Coelho <cristianocc...@gmail.com> wrote:
> 
> Sorry for my above answer I think the actual locks should go like this, so 
> all threads can actually go to the wait line while _populating is True.
> 
> def _populate(self):
> 
>     self.lock.acquire()
>     
>     if self._populating:
>         self.lock.wait()
>         self.lock.release()
>         return
>         
>     self._populating = True
>     
>     self.lock.release()
>     
>     ...
> 
>     self.lock.acquire()
>     self._populating = False
>     self.lock.notify_all()
>     self.lock.release()
> 
> 
> 
> El lunes, 11 de julio de 2016, 22:14:04 (UTC-3), Cristiano Coelho escribió:
> Wouldn't a standard Lock do the trick? Also you are still vulnerable to a 
> race condition when reading self._populating, if the goal is to avoid 
> populating the object more than once in a short interval (in a case where 
> multiple requests hit the server before the object is initialized for the 
> first time?) you are still running all the critical code on all threads if 
> they check self.populating before it is set to True.
> 
> Would a condition work better in this case? Something like this.. (add any 
> missing try/finally/with that might be required), warning, NOT TESTED, just 
> an idea.
> The below code will not be prone to race conditions as the variables are 
> always read/set under a lock, and also the critical section code will be only 
> executed ONCE even if multiple threads attempt to run it at once, while still 
> locking all threads to prevent returning before the code is done.
> 
> def __init__(self, regex, urlconf_name, default_kwargs=None, app_name=None, 
> namespace=None):
>         
>         ...
> 
>     self._populating = False
>     self.lock = threading.Condition()
> 
> def _populate(self):
> 
>     self.lock.acquire()
>     
>     if self._populating:
>         self.lock.wait()
>         self.lock.release()
>         return
>         
>     self._populating = True
> 
>     ...
> 
>     self._populating = False
>     self.lock.notify_all()
>     self.lock.release()
> 
> 
> 
> 
> 
> El lunes, 11 de julio de 2016, 10:08:50 (UTC-3), a.br...@rataran.com <> 
> escribió:
> Hello everyone.
> 
> As suggested by Markus on django-users group, I'm posting this here too.
> 
> -------
> 
> I'm using django (1, 10, 0, u'beta', 1).
> 
> When I try to reverse url in shell everything goes fine.
> 
> When under nginx/uwsgi with many concurrent request I get 
> 
> ... /local/lib/python2.7/site-packages/django/urls/resolvers.py", line 241, 
> in reverse_dict
>     return self._reverse_dict[language_code]
> KeyError: 'it'
> 
> After a wile I figured out that RegexURLResolver is memoized by get_resolver 
> and so it acts like a singleton for a certain number of requests.
> 
> Analyzing the code of  RegexURLResolver I found that the method _poupulate 
> will return directly if it has been called before and not yet finished.
> 
>     ...
>     def _populate(self):
>         if self._populating:
>             return
>         self._populating = True
>     ...  
> 
> if used for recursive call in a single thread this will not hurt, but in my 
> case in uwsgi multi thread mode I got the error.
> 
> here is my quick and dirty fix:
> 
> class RegexURLResolver(LocaleRegexProvider):
>     def __init__(self, regex, urlconf_name, default_kwargs=None, 
> app_name=None, namespace=None):
>         
>         ...
> 
>         self._populating = False
>         self.RLock = threading.RLock()
> 
>         ...
> 
>    def _populate(self):
>         if self._populating:
>             self.RLock.acquire()
>             self.RLock.release()
>             return
>         self._populating = True
>         self.RLock.acquire()
>         
>         ...
> 
>         self._populating = False
>         self.RLock.release()
> 
> 
> Does anyone know if there is a better solution?
> 
> Thank you.
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to django-developers+unsubscr...@googlegroups.com 
> <mailto:django-developers+unsubscr...@googlegroups.com>.
> To post to this group, send email to django-developers@googlegroups.com 
> <mailto:django-developers@googlegroups.com>.
> Visit this group at https://groups.google.com/group/django-developers 
> <https://groups.google.com/group/django-developers>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/django-developers/922ca727-dd60-41dd-9b78-b8d8fe9ebd16%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/django-developers/922ca727-dd60-41dd-9b78-b8d8fe9ebd16%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/79F7081D-FE9C-44DD-8B6E-DC87C040E994%40polytechnique.org.
For more options, visit https://groups.google.com/d/optout.

Reply via email to