[issue29303] asyncio.Lock.acquire() does not always yield

2017-01-17 Thread anonymous2017

New submission from anonymous2017:

Details here: 
http://stackoverflow.com/questions/41708609/unfair-scheduling-bad-lock-optimization-in-asyncio-event-loop

Essentially there should be a `yield` before this line otherwise a coroutine 
that only acquires and releases a lock will never yield to other coroutines.

--
components: asyncio
messages: 285688
nosy: anonymous2017, gvanrossum, yselivanov
priority: normal
severity: normal
status: open
title: asyncio.Lock.acquire() does not always yield
type: behavior
versions: Python 3.6

___
Python tracker 
<http://bugs.python.org/issue29303>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com



[issue29303] asyncio.Lock.acquire() does not always yield

2017-01-17 Thread anonymous2017

anonymous2017 added the comment:

I may have mis-characterized the original report. Rephrasing just to make sure 
it is correctly addressed:

First, it is not about fairness. Sorry for the original characterization. I was 
trying to understand what was happening.

Second, the precise issue is whether a `yield from` can be relied upon for 
cooperative multitasking. Should other co-routines should be prevented from 
running or delayed if one routine is running and acquiring and releasing a lock 
using `yield from`.

It seemed at first sight that `yield from ` should give the scheduler 
a chance to consider other routines. But the lock code above and including line 
#171 does not give control to the scheduler in a special case: 
https://github.com/python/cpython/blob/master/Lib/asyncio/locks.py#L171

Code Sample 1 (shows b() being delayed until a() is fully complete despite a() 
yielding many times)
=
import asyncio

lock = asyncio.Lock()

def a ():
 yield from lock.acquire()
 for i in range(10):
  print('b: ' + str(i))
  if i % 2 == 0:
   lock.release()
   yield from lock.acquire()
 lock.release()

async def b ():
 print('hello')

asyncio.get_event_loop().run_until_complete(asyncio.gather(a(), b()))

print('done')

Code Sample 2
=
(shows interleaving if an additional INITIAL yield from asyncio.sleep is 
inserted; removing the initial sleep removes the interleaving)

import asyncio

lock = asyncio.Lock()

def a ():
 yield from lock.acquire()
 yield from asyncio.sleep(0)
 for i in range(10):
  print('a: ' + str(i))
  if i % 2 == 0:
   lock.release()
   yield from lock.acquire()
 lock.release()

def b ():
 yield from lock.acquire()
 yield from asyncio.sleep(0)
 for i in range(10):
  print('b: ' + str(i))
  if i % 2 == 0:
   lock.release()
   yield from lock.acquire()
 lock.release()

asyncio.get_event_loop().run_until_complete(asyncio.gather(a(), b()))

print('done')


Thank you for your kind consideration.

--

___
Python tracker 
<http://bugs.python.org/issue29303>
___
___
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com