如何确保 while 在各个方面都停止

How to make sure that while will stop in every respect

我正在为 KODI 编写脚本,我发现在出现代码错误时会出现无限循环。这个循环意味着我必须登录到另一个帐户或重新启动我的计算机才能停止 KODI。

因此,我的问题是,如何确保 while 会在各个方面停止?


这只是脚本的一部分,代码包含在 try 中。您还需要知道,如果我提出错误,try 始终有效。

代码中的问题是 while 部分,例如在 p.get()。这导致错误,因为我在调用 get() 之前没有检查工作是否完成(我没有为您更正此错误)。

问题是即使我使用了try,一个意想不到的错误会导致while无法停止!

def browse(separate, page):
    [...]
    # Getting meta data and subtitles
    pools = {'metadata': [], 'subtitles': []}
    with closing(multiprocessing.Pool(processes=2)) as pool:
        provider_meta = call_provider(PROVIDERS['meta_tmdb'])
        provider_subtitle = call_provider(PROVIDERS['subtitle_subscene'])
        for item in items:
            pools['metadata'].append(pool.apply_async(provider_meta.get, args=(item["info"]["code"], item["label"], item["info"]["year"]), callback=pool_stats))
            pools['subtitles'].append(pool.apply_async(provider_subtitle.get, args=(item["info"]["code"], item["label"], item["info"]["year"]), callback=pool_stats))
        pool_checklist = _create_checklist(pools)
        while not xbmc.abortRequested and not dialog.iscanceled():
            xbmc.sleep(100)
            # Check if are raise a error
            for p in pool_checklist:
                p.get()
            # Break when all requests are done 
            if all(p.ready() for p in pool_checklist):
                break
        else:
            return
    [...]

def _create_checklist(pools):
    plist = []
    for c in pools.values():
        for p in c:
            plist.append(p)
    return plist

更新

我不确定 while 是否只会受到 while 中编写的代码的影响,或者是否有其他方面可能会影响 while 过程。


更新 2

一项检查是否 get() returns 错误的测试。使用 Python 3.x 而不是 Python 2.x 进行测试,这是 KODI 使用的。


更新 3

查看是否 get() returns 引发错误的测试。使用 Python 3.4.2 和 Python 2.7.10 进行测试。

from multiprocessing import Pool
from contextlib import closing
import time

def func(x, i):
    if i == 10:
        raise Exception('ttt')
    return {'x':i}

def go():
    try:
        def callback(x):
            print('done: '+str(x['x']))

        pools = []
        with closing(Pool(processes=2)) as pool:
            for i in range(20):
                pools.append(pool.apply_async(func, args=(i,i), callback=callback))
            while not all(p.ready() for p in pools):
                time.sleep(1)

        list = map(lambda p: p.get(), pools)
        for l in list:
            print(l)
        print('Finished with the script')
    except:
        print('ERROR')

if __name__ == '__main__':
    go()

更新 4

问题依旧:


更新 5

似乎没有 while 会在各个方面停止的解决方案。 因此,我认为简单的解决方案是在 while 之后检查池。

def browse(separate, page):
    [...]
    # Getting meta data and subtitles
    pools = {'metadata': [], 'subtitles': []}
    with closing(multiprocessing.Pool(processes=2)) as pool:
        provider_meta = call_provider(PROVIDERS['meta_tmdb'])
        provider_subtitle = call_provider(PROVIDERS['subtitle_subscene'])
        for item in items:
            pools['metadata'].append(pool.apply_async(provider_meta.get, args=(item["info"]["code"], item["label"], item["info"]["year"]), callback=pool_stats))
            pools['subtitles'].append(pool.apply_async(provider_subtitle.get, args=(item["info"]["code"], item["label"], item["info"]["year"]), callback=pool_stats))
        pool_checklist = _create_checklist(pools)
        while not all(p.ready() for p in pool_checklist):
            if xbmc.abortRequested or dialog.iscanceled()
                return
            xbmc.sleep(100)
        # Check the pools for errors
        for p in pool_checklist:
            p.get()
    [...]

def _create_checklist(pools):
    plist = []
    for c in pools.values():
        for p in c:
            plist.append(p)
    return plist

错误不是发生在 get(),而是发生在目标 apply_async()。因此,此解决方案只能再次停止该过程。

结论是。尽管 Pool 出现故障,循环仍将继续,因此您始终可以退出循环。

def browse(separate, page):
    [...]
    # Getting meta data and subtitles
    pools = {'metadata': [], 'subtitles': []}
    with closing(multiprocessing.Pool(processes=2)) as pool:
        provider_meta = call_provider(PROVIDERS['meta_tmdb'])
        provider_subtitle = call_provider(PROVIDERS['subtitle_subscene'])
        for item in items:
            pools['metadata'].append(pool.apply_async(provider_meta.get, args=(item["info"]["code"], item["label"], item["info"]["year"]), callback=pool_stats))
            pools['subtitles'].append(pool.apply_async(provider_subtitle.get, args=(item["info"]["code"], item["label"], item["info"]["year"]), callback=pool_stats))
        pool_checklist = _create_checklist(pools)
        # Loop
        while not all(p.ready() for p in pool_checklist):
            if xbmc.abortRequested or dialog.iscanceled():
                return
            xbmc.sleep(100)
        # Check the results for errors
        for p in pool_checklist:
            p.get()
    [...]

另外注意 Python 3.4.2 和 2.7.10, Pool 只会在完成时引发错误,任何额外的 get() 都可以用来检查结果是否有错误。