Count how many times I visit a thread
I have the following code which is counting how many times I visit a thread. The code is working fine, but I want to find out if that is possible to implement without any global variable involved.
import threading import lib.logging import time count = 0 class Monitor(threading.Thread): def __init__(self, count): threading.Thread.__init__(self) def run(self): global count count+=1 lib.logging.debug ("Count is: " + str(count)) def main(): for i in xrange(3): t1 = Monitor(count) t2 = Monitor(count) t1.start() t2.start() t1.join() t2.join() time.sleep(3) print "done"
How specifically do you want to track it? There is queue and pipe for passing data between threads directly, and Event and Condition if you want an event-driven model.
Can we get a bit more information? What are t1 and t2? If you want count to not be global, you need to be displaying it at a level that has access to both the places it could be found. Ideally, if the print statement can be moved to the same level as the main function, and then add the field self.count to the Monitor class, there could be a function which checks the values of count from all monitor classes, and then prints the sum if it has changed.
2 Answers 2
It is possible to count function call without global variable using itertools.count and python’s function default arguments behaviour:
import threading import lib.logging import time from itertools import count class Monitor(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self, count=count()): # next(count) starts from 0, so to log first '1', + 1 is used lib.logging.debug ("Count is: " + str(next(count) + 1)) def main(): for i in xrange(3): t1 = Monitor() t2 = Monitor() t1.start() t2.start() t1.join() t2.join() time.sleep(3) print "done"
One possible solution is to use a «semi-persisted» in memory counter.
#!/usr/bin/env python # -*- coding: utf-8 -*- import threading import time import redis class RedisCounter(object): def __init__(self, db, host, port, key, reset=False): pool = redis.ConnectionPool(host=host, port=port, db=db) self.conn = redis.StrictRedis(connection_pool=pool) self.key = key if reset: self.initialize() def initialize(self): self.conn.set(self.key, 0) def incr(self): self.conn.incr(self.key) def get(self): return int(self.conn.get(self.key)) class Monitor(threading.Thread): def __init__(self, counter): threading.Thread.__init__(self) self.counter = counter def run(self): self.counter.incr() print("Count is: " + str(self.counter.get())) def main(): counter = RedisCounter(0, 'localhost', 6379, 'thread_counter', True) for i in xrange(3): t1 = Monitor(counter) t2 = Monitor(counter) t1.start() t2.start() t1.join() t2.join() time.sleep(3) print "done" if __name__ == '__main__': main()
This might be an overkill for you, but a direction of solving such a problem nonetheless 🙂
Number of active threads
My question is, why is the number of active threads being reported as 2 and why does the list generated by enumerate contain the main thread as well. I was thinking that the main thread terminates after spawning «MyThread1». $ ./threadeg.py
i is: 0 2 [<_MainThread(MainThread, stopped 139858183157504)>, ] i is: 1 2 [<_MainThread(MainThread, stopped 139858183157504)>, ] i is: 2 2 [<_MainThread(MainThread, stopped 139858183157504)>, ] i is: 3 2 [<_MainThread(MainThread, stopped 139858183157504)>, ] i is: 4 2 [<_MainThread(MainThread, stopped 139858183157504)>, ]
@Cairnarvon What is the source of your reference based on which you are making the statement? Can I please know?
1 Answer 1
threading.activeCount() which returns the number of threads active (that were started with that module). [Source]
Since the threading module is a pure python module built on top of the thread module, it’s pretty easy to view the source code.
Here is the source code for active_count
def activeCount(): """Return the number of Thread objects currently alive. The returned count is equal to the length of the list returned by enumerate(). """ with _active_limbo_lock: return len(_active) + len(_limbo)
upon further investigation it should be noted that there is a _MainThread instance is stored in _active (_active and _limbo are both dictionaries that map thread names to their instances). And is deleted from _active when _exitfunc is called.
Here is the source for _MainThread,
class _MainThread(Thread): def __init__(self): Thread.__init__(self, name="MainThread") self._Thread__started.set() self._set_ident() with _active_limbo_lock: _active[_get_ident()] = self def _set_daemon(self): return False def _exitfunc(self): self._Thread__stop() t = _pickSomeNonDaemonThread() if t: if __debug__: self._note("%s: waiting for other threads", self) while t: t.join() t = _pickSomeNonDaemonThread() if __debug__: self._note("%s: exiting", self) self._Thread__delete()
once _exitfunc is called _MainThread waits for all non daemon threads to join and then calls Thread._delete which in this case has been mangled to __Thread_delete which in turn removes _MainThread from the _active dictionary.
_exitfunc is assigned to _shutdown on line 1201.
_shutdown = _MainThread()._exitfunc
_shutdown is called from pythonrun.c, which in turn is called by Py_Finalize . Py_Finalize is called by Py_Exit, which exits the main process (at this point only daemons are left).
Exit the current process. This calls Py_Finalize() and then calls the standard C library function exit(status).
Here is an example to get you the behavior you expect.
import threading, time def f(): time.sleep(1) #wait for the interpreter to "shutdown" print threading.enumerate() if __name__ == '__main__': t = threading.Thread(target=f) t.daemon = True t.start() threading._shutdown() #simulate an interpreter shutdown
Another great answer describing how threads are shutdown.
№34 Потоки и многопоточность / для начинающих
Модуль threading в Python используется для реализации многопоточности в программах. В этом материале разберемся с Thread и разными функциями этого модуля.
Что такое поток?
В информатике поток — это минимальная единица работы, запланированная для выполнения операционной системой.
О потоках нужно знать следующее:
- Они существуют внутри процесса;
- В одном процессе может быть несколько потоков;
- Потоки в одном процессе разделяют состояние и память родительского процесса.
Модуль threading в Python можно представить таким простым примером:
import time
from threading import Thread
def sleepMe(i):
print("Поток %i засыпает на 5 секунд.\n" % i)
time.sleep(5)
print("Поток %i сейчас проснулся.\n" % i)
for i in range(10):
th = Thread(target=sleepMe, args=(i, ))
th.start()После запуска скрипта вывод будет следующий:
Поток 0 засыпает на 5 секунд. Поток 3 засыпает на 5 секунд. Поток 1 засыпает на 5 секунд. Поток 4 засыпает на 5 секунд. Поток 2 засыпает на 5 секунд. Поток 5 засыпает на 5 секунд. Поток 6 засыпает на 5 секунд. Поток 7 засыпает на 5 секунд. Поток 8 засыпает на 5 секунд. Поток 9 засыпает на 5 секунд. Поток 0 сейчас проснулся. Поток 3 сейчас проснулся. Поток 1 сейчас проснулся. Поток 4 сейчас проснулся. Поток 2 сейчас проснулся. Поток 5 сейчас проснулся. Поток 6 сейчас проснулся. Поток 7 сейчас проснулся. Поток 8 сейчас проснулся. Поток 9 сейчас проснулся.
У вас он может отличаться, потому что у параллельных потоков нет определенного порядка.
Функции threading в Python
Возьмем программу из первого примера и воспользуемся ею для демонстрации разных функций модуля.
threading.active_count()
Эта функция возвращает количество исполняемых на текущий момент потоков. Изменим последнюю программу, чтобы она выглядела вот так:
import time
import threading
from threading import Thread
def sleepMe(i):
print("Поток %i засыпает на 5 секунд." % i)
time.sleep(5)
print("Поток %i сейчас проснулся." % i)
for i in range(10):
th = Thread(target=sleepMe, args=(i, ))
th.start()
print("Запущено потоков: %i." % threading.active_count())Теперь в выводе будет показываться количество активных на текущий момент потоков:
Поток 0 засыпает на 5 секунд.Запущено потоков: 3. Запущено потоков: 4.Поток 1 засыпает на 5 секунд. Запущено потоков: 5.Поток 2 засыпает на 5 секунд. Поток 3 засыпает на 5 секунд.Запущено потоков: 6. Запущено потоков: 7.Поток 4 засыпает на 5 секунд. Поток 5 засыпает на 5 секунд.Запущено потоков: 8. Поток 6 засыпает на 5 секунд.Запущено потоков: 9. Запущено потоков: 10.Поток 7 засыпает на 5 секунд. Поток 8 засыпает на 5 секунд.Запущено потоков: 11. Поток 9 засыпает на 5 секунд.Запущено потоков: 12. Поток 0 сейчас проснулся. Поток 1 сейчас проснулся. Поток 2 сейчас проснулся. Поток 3 сейчас проснулся. Поток 4 сейчас проснулся. Поток 5 сейчас проснулся. Поток 6 сейчас проснулся. Поток 7 сейчас проснулся. Поток 8 сейчас проснулся. Поток 9 сейчас проснулся.
Также обратите внимание, что после запуска всех потоков счетчик показывает число 11, а не 10. Причина в том, что основной поток также учитывается наравне с 10 остальными.
threading.current_thread()
Эта функция возвращает исполняемый прямо сейчас поток. С ее помощью можно выполнять определенные действия с ним. Поменяем все тот же скрипт: