协程和资源获取的结合似乎可能会产生一些意想不到的(或不直观的)后果。
基本问题是这样的方法是否有效:
def coroutine():
with open(path, 'r') as fh:
for line in fh:
yield line
确实如此。 (你可以测试一下!)
更深层的担忧是with
应该是替代品finally
,您可以确保在块末尾释放资源。协程可以暂停和恢复执行within the with
块,所以冲突如何解决?
例如,如果在协程尚未返回时打开一个在协程内部和外部都具有读/写功能的文件:
def coroutine():
with open('test.txt', 'rw+') as fh:
for line in fh:
yield line
a = coroutine()
assert a.next() # Open the filehandle inside the coroutine first.
with open('test.txt', 'rw+') as fh: # Then open it outside.
for line in fh:
print 'Outside coroutine: %r' % repr(line)
assert a.next() # Can we still use it?
Update
在前面的示例中,我打算进行写锁定文件句柄争用,但由于大多数操作系统为每个进程分配文件句柄,因此不会出现争用。 (感谢 @Miles 指出这个例子没有太大意义。)这是我修改后的例子,它显示了真正的死锁条件:
import threading
lock = threading.Lock()
def coroutine():
with lock:
yield 'spam'
yield 'eggs'
generator = coroutine()
assert generator.next()
with lock: # Deadlock!
print 'Outside the coroutine got the lock'
assert generator.next()
我真的不明白你要问什么冲突,也不明白这个例子的问题:同一个文件有两个共存、独立的句柄很好。
我在回答你的问题时不知道的一件事是,生成器上有一个新的 close() 方法:
close()
提出了一个新的GeneratorExit
生成器内部出现异常以终止迭代。收到此异常后,生成器的代码必须引发GeneratorExit
or StopIteration
.
close()
当生成器被垃圾收集时被调用,因此这意味着生成器的代码在生成器被销毁之前有最后一次运行机会。这最后的机会意味着try...finally
现在可以保证生成器中的语句有效;这finally
子句现在总是有机会运行。这看起来像是一个很小的语言琐事,但是使用生成器和try...finally
实际上有必要为了实施with
PEP 343 描述的声明。
http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-features http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-features
这样就可以处理以下情况:with
语句在生成器中使用,但它在中间产生但从未返回——上下文管理器的__exit__
当生成器被垃圾收集时,将调用该方法。
Edit:
关于文件句柄问题:我有时会忘记存在不类似 POSIX 的平台。 :)
就锁而言,我认为 Rafał Dowgird 所说的“你只需要意识到发电机就像任何其他拥有资源的物体一样”一语中的。我不认为with
语句在这里确实很相关,因为这个函数也遇到了同样的死锁问题:
def coroutine():
lock.acquire()
yield 'spam'
yield 'eggs'
lock.release()
generator = coroutine()
generator.next()
lock.acquire() # whoops!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)