Поддерживать автоматически очищаемый список потоков в Python - PullRequest
4 голосов
/ 28 мая 2020

У меня есть список threads, и я хочу автоматически удалять потоки из списка, когда они завершены .

Я нашел этот метод:

import threading, time

def f(seconds, info):
    print('starting', seconds)
    time.sleep(seconds)
    print('finished', seconds)
    threads.remove(info['thread'])

def newaction(seconds):
    info = {}
    thread = threading.Thread(target=f, args=(seconds, info))
    info['thread'] = thread
    thread.start()
    threads.append(thread)

threads = []
newaction(1)
newaction(2)
for _ in range(10):
    time.sleep(0.3)
    print(threads)

Он работает:

starting 1
starting 2
[<Thread(Thread-1, started 1612)>, <Thread(Thread-2, started 712)>]
[<Thread(Thread-1, started 1612)>, <Thread(Thread-2, started 712)>]
[<Thread(Thread-1, started 1612)>, <Thread(Thread-2, started 712)>]
finished 1
[<Thread(Thread-2, started 712)>]
[<Thread(Thread-2, started 712)>]
[<Thread(Thread-2, started 712)>]
finished 2
[]
[]
[]
[]

Но факт передачи dict info - это немного взлом. Я использовал его, потому что, очевидно, я не могу передать thread в args ...

thread = threading.Thread(target=f, args=(seconds, thread))  
#                                                     ^ not created yet!

... когда объект Thread еще не создан!

Есть ли более естественный способ в Python поддерживать автоматически очищаемый список потоков?

Ответы [ 3 ]

2 голосов
/ 01 июня 2020

У вас есть функция current_thread().

import threading, time

def f(seconds):
    print('starting', seconds)
    time.sleep(seconds)
    print('finished', seconds)
    threads.remove(threading.current_thread())

def newaction(seconds):
    thread = threading.Thread(target=f, args=(seconds,))
    thread.start()
    threads.append(thread)

threads = []
newaction(1)
newaction(2)
for _ in range(10):
    time.sleep(0.3)
    print(threads)

Вывод:

starting 1
starting 2
[<Thread(Thread-1, started 4588)>, <Thread(Thread-2, started 4388)>]
[<Thread(Thread-1, started 4588)>, <Thread(Thread-2, started 4388)>]
[<Thread(Thread-1, started 4588)>, <Thread(Thread-2, started 4388)>]
finished 1
[<Thread(Thread-2, started 4388)>]
[<Thread(Thread-2, started 4388)>]
[<Thread(Thread-2, started 4388)>]
finished 2
[]
[]
[]
[]
1 голос
/ 07 июня 2020

Создание подкласса Thread приводит к решению с естественным синтаксисом и безопасным местом для хранения списка потоков. Вам также не нужно включать инструкцию для удаления потока в конце каждой функции, которую вы хотите запустить в другом потоке. Просто используйте подкласс.

import threading, time

class AutoRemovingThread(threading.Thread):
  threads = []
  def __init__(self, func, *args, **kwargs):
    super().__init__()
    self.threads.append(self)
    self.func = func
    self.args = args
    self.kwargs = kwargs
  def run(self):
    self.func(*self.args, **self.kwargs)
    self.threads.remove(self)

def f(seconds):
  print('starting', seconds)
  time.sleep(seconds)
  print('finished', seconds)

def newaction(seconds):
  AutoRemovingThread(f, seconds).start()

newaction(1)
newaction(2)
for _ in range(10):
  time.sleep(0.3)
  print(AutoRemovingThread.threads)

Вывод:

starting 1
starting 2
[<AutoRemovingThread(Thread-1, started 8436)>, <AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-1, started 8436)>, <AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-1, started 8436)>, <AutoRemovingThread(Thread-2, started 1072)>]
finished 1
[<AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-2, started 1072)>]
[<AutoRemovingThread(Thread-2, started 1072)>]
finished 2
[]
[]
[]
[]

python-3.8

0 голосов
/ 28 мая 2020
import threading

def get_status_of_threads():
    current_threads = threading.enumerate()

    thread_data = []

    for item in current_threads:
        try:
            print(str(item.target))
        except AttributeError:
            print("item", str(item))
        thread_data.append({"thread_name": item.getName(), "status": int(item.is_alive()), "id": item.ident})
    return thread_data

Приведенный выше код протестирован в Python2 .7, вы можете использовать его в отдельном потоке, если хотите непрерывно отслеживать потоки, или вы можете предоставить это как API, чтобы вы могли проверять каждый раз, когда вы хотеть. Это также поможет сократить потери ресурсов для того же.

Для API вы можете использовать функцию json2html.convert({"thread_data":thread_data}), чтобы отображать его более эстетично c в табличной форме.

...