Python 如何在concurrent.futures.ThreadPoolExecutor中使用锁而不导致死锁?

Python 如何在concurrent.futures.ThreadPoolExecutor中使用锁而不导致死锁?,python,multithreading,concurrent.futures,Python,Multithreading,Concurrent.futures,我正在处理Jira changelog历史数据,由于数据量很大,而且大多数处理时间都是基于I/O的,因此我认为异步方法可能会很好地工作 我有一个所有issue\u id的列表,我将其输入一个函数,该函数通过jira pythonapi发出请求,将信息提取到dict,然后通过传入的DictWriter将其写出。为了保证线程安全,我从threading模块导入了一个Lock()。在测试中,它似乎在某一点陷入僵局,只是挂起。我在文档中注意到,如果任务相互依赖,那么它们可以挂起,我想这是由于我正在实现的

我正在处理Jira changelog历史数据,由于数据量很大,而且大多数处理时间都是基于I/O的,因此我认为异步方法可能会很好地工作

我有一个所有
issue\u id
的列表,我将其输入一个函数,该函数通过
jira python
api发出请求,将信息提取到
dict
,然后通过传入的
DictWriter
将其写出。为了保证线程安全,我从
threading
模块导入了一个
Lock()。在测试中,它似乎在某一点陷入僵局,只是挂起。我在文档中注意到,如果任务相互依赖,那么它们可以挂起,我想这是由于我正在实现的锁造成的。我怎样才能防止这种情况发生

以下是我的代码供参考:

(此时代码中有一个名为
keys
的列表,其中包含所有问题id)


编辑:我也很可能被Jira API限制了。

您需要将
exec
的结果存储到一个列表中,通常命名为
futs
,然后循环调用该列表
result()
,以获得结果,处理可能发生的任何错误

(我还想将
exec
转换为
executor
,因为这更为传统,而且可以避免覆盖内置的)

def write_issue_history(
        jira_instance: JIRA,
        issue_id: str,
        writer: DictWriter,
        lock: Lock):
    logging.debug('Now processing data for issue {}'.format(issue_id))
    changelog = jira_instance.issue(issue_id, expand='changelog').changelog

    for history in changelog.histories:
        created = history.created
        for item in history.items:
            to_write = dict(issue_id=issue_id)
            to_write['date'] = created
            to_write['field'] = item.field
            to_write['changed_from'] = item.fromString
            to_write['changed_to'] = item.toString
            clean_data(to_write)
            add_etl_fields(to_write)
            print(to_write)
            with lock:
                print('Lock obtained')
                writer.writerow(to_write)

if __name__ == '__main__':
    with open('outfile.txt', 'w') as outf:
                writer = DictWriter(
                    f=outf,
                    fieldnames=fieldnames,
                    delimiter='|',
                    extrasaction='ignore'
                )
                writer_lock = Lock()
                with ThreadPoolExecutor(max_workers=5) as exec:
                    for key in keys[:5]:
                        exec.submit(
                            write_issue_history,
                            j,
                            key,
                            writer,
                            writer_lock
                        )
from traceback import print_exc

...

with ThreadPoolExecutor(max_workers=5) as executor:
    futs = []
    for key in keys[:5]:
        futs.append( executor.submit(
            write_issue_history,
            j,
            key,
            writer,
            writer_lock)
        )

for fut in futs:
    try:
        fut.result()
    except Exception as e:
        print_exc()