Python threading глобальные переменные

Русские Блоги

Глобальные переменные Python с многопоточным доступом

Глобальные переменные, разделяемые многопоточностью

Глобальные переменные, разделяемые многопоточностью

import threading import time g_num = 200 def test1(): global g_num for i in range(5): g_num += 1 print("--test1, g_num = %d--" % g_num) def test2(): global g_num print("--test2, g_num = %d--" % g_num) if __name__ == "__main__": print ("- Перед выполнением потока g_num =% d -"% g_num) t1 = threading.Thread(target=test1) t1.start() # Задержка на некоторое время, чтобы убедиться, что что-то в потоке t1 может быть выполнено time.sleep(1) t2 = threading.Thread(target=test2) t2.start()
- Перед выполнением потока g_num = 200 - --test1, g_num = 205-- --test2, g_num = 205--

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

Список передается в поток как аргументы

import threading import time def test1(nums): nums.append(54) print("--test1, nums=", nums) g_nums = [1, 8, 9] def test2(nums): # Убедитесь, что выполнение test1 завершено time.sleep(1) print("--test2, nums=", nums) if __name__ == "__main__": t1 = threading.Thread(target=test1, args=(g_nums,)) t1.start() t2 = threading.Thread(target=test2, args=(g_nums,)) t2.start() 
--test1, nums= [1, 8, 9, 54] --test2, nums= [1, 8, 9, 54]

подводить итоги

  • Все потоки в процессе совместно используют глобальные переменные, что удобно для обмена данными между несколькими потоками.
  • Недостатком является то, что потоки произвольно изменяют глобальные переменные, что может вызвать путаницу в отношении глобальных переменных между несколькими потоками (т.е. поток небезопасен).
Читайте также:  Android sqlite java example

Глобальные переменные, разделяемые многопоточностью

Проблемы, которые могут возникнуть при многопоточной разработке

Предполагая, что два потока t1 и t2 должны добавить 1 к глобальной переменной g_num (по умолчанию 0), t1 и t2 каждый добавляют по 10 раз к g_num, и конечный результат g_num должен быть 20.

Однако из-за одновременной работы нескольких потоков могут возникнуть следующие ситуации:

  1. Когда g_num = 0, t1 получает g_num = 0. В это время система переводит t1 в состояние «сна», преобразует t2 в состояние «работает», а t2 также получает g_num = 0.
  2. Затем t2 добавляет 1 к полученному значению и присваивает его g_num, так что g_num = 1
  3. Затем система переводит t2 в режим ожидания, а t1 — в режим работы. Поток t1 добавляет 1 к полученному ранее 0 и присваивает его g_num.
  4. В результате, хотя t1 и t2 оба добавляют 1 к g_num, результат все равно g_num = 1

Тест 1

import threading import time g_num = 0 def test1(num): global g_num for i in range(num): g_num += 1 print("--test1, g_num = %d--" % g_num) def test2(num): global g_num for i in range(num): g_num += 1 print("--test2, g_num = %d--" % g_num) if __name__ == "__main__": print ("- Перед созданием потока g_num =% d -"% g_num) t1 = threading.Thread(target=test1, args=(100,)) t1.start() t2 = threading.Thread(target=test2, args=(100,)) t2.start() while len(threading.enumerate()) != 1: time.sleep(1) print ("Окончательный результат: g_num =% d"% g_num) 
- Перед созданием потока g_num = 0 - --test1, g_num = 100-- --test2, g_num = 200-- Окончательный результат: g_num = 200

Тест 2

На основе теста 1 значение параметра, переданного в методы test1 и test2, составляет: 9999999

- Перед созданием потока g_num = 0 - --test1, g_num = 13554011-- --test2, g_num = 13571206-- Окончательный результат: g_num = 13571206

Очевидно, ожидаемый результат: 9999999 + 9999999 = 19999998, а текущий результат: 13571206.

Источник

Threading Return Values in Python

You can return values from a thread via instance variables on the threading.Thread class or via global variables.

Читайте также:  Где найти qt designer python

In this tutorial you will discover how to return values from a thread.

Need to Return Values From a Thread

A thread is a thread of execution in a computer program.

Every Python program has at least one thread of execution called the main thread. Both processes and threads are created and managed by the underlying operating system.

Sometimes we may need to create additional threads in our program in order to execute code concurrently.

Python provides the ability to create and manage new threads via the threading module and the threading.Thread class.

You can learn more about Python threads in the guude:

When using new threads, we may need to return a value from the thread to another thread, such as the main thread.

This may be for many reasons, such as:

  • The new thread loaded some data that needs to be returned.
  • The new thread calculated something that needs to be returned.
  • The new thread needs to share its state or status with another thread.

How can we return values from a thread in Python?

Run your loops using all CPUs, download my FREE book to learn how.

How to Return Values From a Thread

A thread cannot return values directly.

The start() method on a thread calls the run() method of the thread that executes our code in a new thread of execution. The run() method in turn may call a target function, if configured.

The start() method does not block, instead it returns immediately and does not return a value. The run method also does not return a value.

We can join a new thread from the current thread and block until the new thread terminates, but the join() method also does not return a value.

Instead, we must return values from a thread indirectly.

There are two main ways to return values from a thread, they are:

  • Extend threading.Thread and store data in instance variables.
  • Store data in global variables.

The preferred approach is to extend the threading.Thread class and store return data as instance variables.

This involves defining a new class that extends the threading.Thread and defines a constructor that calls the parent constructor.

The run() method can be defined that executes the custom code in a new thread and stores data as instance variables.

Источник

How to Share Variables Between Threads in Python

You can protect data variables shared between threads using a threading.Lock mutex lock, and you can share data between threads explicitly using queue.Queue.

In this tutorial you will discover how to share data between threads safely.

Need to Share Data Between Threads

A thread is a thread of execution in a computer program.

Every Python program has at least one thread of execution called the main thread. Both processes and threads are created and managed by the underlying operating system.

Sometimes we may need to create additional threads in our program in order to execute code concurrently.

Python provides the ability to create and manage new threads via the threading module and the threading.Thread class.

You can learn more about Python threads in the guide:

In concurrent programming we may need to share data between threads.

Data may refer to many different things, such as:

It could be something as simple as a counter or a boolean flag, to application specific data and data structures.

We may need to share data for many reasons because multiple threads need to read and/or write to the same data variable.

The problem with multiple threads reading and writing the same variable is that it can result in a concurrency failure mode called a race condition.

You can learn more about race conditions here:

How can we share data between threads safely?

Run your loops using all CPUs, download my FREE book to learn how.

How to Share Data Between Threads

There are many ways to share data between threads safely.

The specific method to use depends on the type of data to be shared.

Three common approaches include:

  • Sharing a boolean variable with a threading.Event.
  • Protecting shared data with a threading.Lock.
  • Sharing data with a queue.Queue.

Let’s take a closer look at each in turn.

Share a Boolean Variable with an Event

When sharing a boolean flag, an event can be used via the thread.Event class.

The event class will protect a boolean variable ensuring all access and change to the variable is thread safe, avoiding race conditions.

The event can be created in the unset or False state.

It can then be shared between threads.

The status of the event can be checked safely via the is_set() function.

The value event can be changed by multiple different threads. It can be set to True via the set() function and set False via the clear() function.

You can learn more about the event here:

Access Shared Data With a Lock

When sharing ad hoc variables between threads, a mutual exclusion lock (mutex) can be used via the threading.Lock class.

A lock can be used to protect one or multiple shared variables and they may be variables of any type. The shared variables will be protected from race conditions as long as all access and changes to the variables are protected by the lock.

Each thread interested in the variable must first acquire the lock, and then release it once they are finished with the variable. This will ensure that only one thread can access the variable at a time. A thread trying to acquire the lock that has already been acquired must wait until the lock has been released again.

This can be achieved using the acquire() and release() functions, for example:

Источник

Как поделиться переменными между потоками из разных модулей?

1) Как расшарить переменные на другой модуль?
2) Правильно понимаю что поток независимо от места вызова(main.py) всегда будет использовать набор переменных из модуля где находится target (extra_thread.py)?

import threading import time from extra_thread import f # импортируем функцию из другого файла для потока v = 1 threading.Thread(target=f).start() # функция меняет значение v time.sleep(0.3) print(v) # в итоге значение v = 1

Не используйте глобальные переменные. Не используйте глобальные переменные в конкурентной среде ещё сильнее.

Vindicar

Для начала скажи, какую задачу ты пытаешься решить.
Для случая с одноразовым потоком-воркером, тебе не нужна глобальная переменная. Достаточно класса.

import threading class MyWorkerThread(threading.Thread): def __init__(self, arg1: float, arg2: float): # передаём потоку входные данные # поток не должен их менять! super().__init__() self.arg1 = arg1 self.arg2 = arg2 self.result: t.Optional[float] = None def run(self): time.sleep(10) # имитируем длительную работу self.result = self.arg1 + self.arg2
worker = MyWorkerThread(42, 69) worker.start() while True: if worker.is_alive(): # проверяем, жив ли поток # делаешь ещё что-то, пока поток работает print('Still working. ') time.sleep(0.5) else: # поток завершился, даём знать пользователю. print(f'Done! Result is !') break # выходим из цикла

Если же тебе нужно просто дождаться конца потока, ничего не делая в процессе, можно сделать просто worker.join()

Сложности начинаются, когда тебе нужно взаимодействовать с длительным потоком. Усложним пример:

import threading, queue class MyWorkerThread(threading.Thread): def __init__(self, arg1: float, arg2: float): # передаём потоку входные данные # поток не должен их менять! super().__init__() self.arg1 = arg1 self.arg2 = arg2 self.result: t.Optional[float] = None self.progress = queue.Queue() def run(self): for i in range(10): time.sleep(1) # имитируем длительную работу self.progress.put(i/10) # сообщаем о прогрессе self.result = self.arg1 + self.arg2 self.progress.put(1.00)
worker = MyWorkerThread(42, 69) worker.start() while True: if worker.is_alive(): # проверяем, жив ли поток # делаешь ещё что-то, пока поток работает try: progress = worker.progress.get(block=True, timeout=0.5) except queue.Empty: # поток ничего не сообщил print('Still working. ') else: print(f'Still working. ') worker.progress.task_done() # один вызов task_done() на один успешный вызов get()! else: # поток завершился, даём знать пользователю. print(f'Done! Result is !') break # выходим из цикла

Источник

Оцените статью