Recursive @threadpool_limits.wrap() calls do not behave as expected when recursing

Fechada
#293 3 comentários 1 reação 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

Um pull request relacionado já foi integrado.

  • #294 de @itamarst — integrado

Avaliação

Dificuldade
4/5
Tempo estimado
3-5 dias
Facilidade para iniciantes
35/100
Tipo de issue
Bug
Clareza
Razoavelmente clara
Status de atividade
Ativa
Stack de tecnologia
python
Domínio
performance

Direção de pesquisa

The failing case is the test test_recursive_wrap_releases_the_shared_pool_claim, which needs a non-OpenMP OpenBLAS build with at least two threads. Start by running it with recurse(1) and reading how threadpool_limits.wrap restores limits and releases the controlling thread on return. Done when the test passes with recurse(1) and the existing recursion behaviour still holds.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

Returning from a wrapped function should return to the previous level of thread limits at the time they were called, even in the face of recursion. That's not what happens in practice, though.

The following test fails on both master and 3.7 (i.e. it's not due to the controlling thread changes), but passes if recurse(1) is switched to recurse(0).

from threading import Thread

from threadpoolctl import threadpool_limits, ThreadpoolController

import numpy
import pytest

def run_in_thread(f, *args, **kwargs):
    thread = Thread(target=lambda: f(*args, **kwargs))
    thread.start()
    thread.join()
    return thread


def _non_openmp_openblas():
    openblas = ThreadpoolController().select(internal_api="openblas")
    if not openblas:
        pytest.skip("requires OpenBLAS.")
    libs = []
    seen = set()
    for lib in openblas.lib_controllers:
        if lib.threading_layer == "openmp" or lib.filepath in seen:
            continue
        seen.add(lib.filepath)
        libs.append(lib)
    if not libs:
        pytest.skip("require non-OpenMP OpenBLAS.")
    return libs


def _require_resizable_non_openmp_openblas():
    libs = _non_openmp_openblas()
    lib = libs[0]
    orig = lib.get_num_threads()
    if orig is None or orig < 2:
        pytest.skip("Test requires a non-OpenMP OpenBLAS with at least 2 threads")
    return lib, orig


def test_recursive_wrap_releases_the_shared_pool_claim():
    # One wrapped function calling itself must keep the limit between the inner
    # return and the outer return, then restore the original count and drop the
    # controlling thread. Another thread can then set the count.
    lib, orig = _require_resizable_non_openmp_openblas()

    @threadpool_limits.wrap(limits=1, user_api="blas")
    def recurse(depth):
        assert lib.get_num_threads() == 1
        if depth:
            recurse(depth - 1)
            assert lib.get_num_threads() == 1

    recurse(1)
    assert lib.get_num_threads() == orig

    observed = {}

    def other_thread():
        lib.set_num_threads(1)
        observed["threads"] = lib.get_num_threads()

    worker = run_in_thread(other_thread)
    assert observed["threads"] == 1
Linguagem predominante
Python
Estrelas
434
Forks
38
Merge médio
1d 4h
PRs com merge (30d)
18

Preparar o ambiente

Este projeto não oferece contêiner de desenvolvimento, Dockerfile nem guia de contribuição, então a configuração fica por sua conta: comece pelo README e veja nosso guia da primeira contribuição para os passos gerais.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de joblib/threadpoolctl

Todas as issues de joblib/threadpoolctl

Issues semelhantes

Mais issues de Python

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.