Я давно не обновлял свой блог, и мне стало лень к празднику Весны дома -_-, но я обещаю вам закончить эту вводную серию по питону, а я продолжу усердно работать! желаю всем счастливого нового года и все будет хорошо!
концепция потока
Многие языки программирования, которые мы изучаем, такие как java, oc и т. д., имеют концепцию потоков. Потоки широко используются и приносят много удобства в нашу разработку. Они в основном используются для некоторой последовательной или параллельной логической обработки, например as Когда кнопка нажата, мы можем контролировать время выполнения потока с помощью индикатора выполнения для лучшего взаимодействия с пользователем.
Каждый независимый поток содержит вход в программу, последовательную последовательность выполнения и выход из программы.Поток должен существовать в программе, но не может работать независимо от программы!
Каждый поток имеет свой собственный набор памяти процессора, называемый контекстом потока, который отражает состояние регистров процессора на момент последнего запуска потока.Регистры указателя инструкций и указателя стека являются двумя наиболее важными регистрами в контексте потока. выполняется в контексте процесса, и эти адреса используются для маркировки памяти в адресном пространстве процесса, которому принадлежит поток.
Потоки Python
В Python в основном предусмотрены два модуля потока, поток и поток. Модуль потока предоставляет самые основные и низкоуровневые функции потока и простую блокировку. Модуль потока представляет собой расширенную инкапсуляцию модуля потока и предоставляет множество потоков. Свойства и методы Ниже мы проанализируем два модуля один за другим.
модуль потока (устаревший)
Часто используемые функциональные методы модуля потока:
Имя функции | описывать |
---|---|
start_new_thread(function, args, kwargs=None) | Создать новый поток, function — это имя функции, которая должна быть запущена потоком, args — параметр функции (тип кортежа), а kwargs — необязательный параметр. |
allocate_lock() | Выделите объект блокировки потока типа LockType |
exit() | выход потока |
_count() | Возвращает количество потоков, обратите внимание, что основной поток не включен, поэтому метод возвращает 0 при запуске метода в основном потоке. |
locked | блокировка locktype, возвращает true для блокировки |
release() | Снять блокировку объекта locktype |
acquire() | запирание |
Возьмем пример:
import thread,time
def loop1():
print '线程个数-' + str(thread._count())
i=0
try:
while i < 100:
print i
time.sleep(1)
i = i + 1
except Exception as e:
print e
thread.start_new_thread(loop1,())
Запустив приведенный выше код, вы обнаружите, что печать цикла в методе loop1 не вызывается, а напрямую возвращает исключение:
Unhandled exception in thread started by
sys.excepthook is missing
lost sys.stderr
В это время вы можете снова и снова проверять код, думая, что код неверен (да, этот человек — я), на самом деле, сам наш код не является неправильным, это дефект модуля потока раннего Python. (этот дефект также стал причиной этого. Основная причина, по которой модуль официально объявлен устаревшим): Когда мы используем start_new_thread для создания нового потока в основном потоке, основной поток не может знать, когда поток заканчивается, и он не знает, сколько ждать , так что основной поток завершил выполнение, дочерний поток не завершился, поэтому система выдает это исключение.
Есть два способа разрешить это исключение:
1. Позвольте основному потоку спать достаточно долго, чтобы дождаться, пока дочерний поток вернет результат:
import thread,time
def loop1():
print '线程个数-' + str(thread._count())
i=0
try:
while i < 100:
print i
time.sleep(1)
i = i + 1
except Exception as e:
print e
thread.start_new_thread(loop1,())
time.sleep(1000) #让主线程休眠1000秒,足够子线程完成
2. Заблокируйте поток (ранние потоки Python используют общую обработку)
import thread,time
def loop1(lock):
print '线程个数-' + str(thread._count())
i=0
try:
while i < 100:
print i
time.sleep(1)
i = i + 1
except Exception as e:
lock.release()
print e
lock.release() #执行完毕,释放锁
lock=thread.allocate_lock() #获取locktype对象
lock.acquire() #锁定
thread.start_new_thread(loop1,(lock,))
while lock.locked(): #等待线程锁释放
pass
Выше приведено обычное использование потока модуля потока. Мы видим, что работа с потоком, предоставляемая модулем потока, чрезвычайно ограничена и очень негибка в использовании. Давайте представим его аналогичный модуль потока.
Модуль для резьбы (рекомендуется)
Модуль threading — это совершенство работы с потоками, он имеет набор зрелых методов работы с потоками, которые могут в основном выполнять все необходимые нам операции с потоками.
Распространенные методы нарезки:
- threading.currentThread(): возвращает текущую переменную потока.
- threading.enumerate(): возвращает список запущенных потоков. Работает после запуска потока и до конца, исключая поток до начала и после конца.
- threading.activeCount(): возвращает количество запущенных потоков, имеет тот же результат, что и len(threading.enumerate()).
- run(): метод, используемый для представления активности потока.
- start(): начать активность потока.
- join([time]): Подождите, пока поток завершится. Это блокирует вызывающий поток до тех пор, пока метод потока join() не будет вызван для прерывания - выхода в обычном режиме или создания необработанного исключения - или до тех пор, пока не произойдет необязательный тайм-аут.
- isAlive(): возвращает, активен ли поток.
- getName(): возвращает имя потока.
- setName(): установить имя потока.
Модуль для резьбы создает потоки двумя способами:
1. Создайте непосредственно путем инициализации объекта потока:
#coding=utf-8
import threading,time
def test():
t = threading.currentThread() # 获取当前子线程对象
print t.getName() # 打印当前子线程名字
i=0
while i<10:
print i
time.sleep(1)
i=i+1
m=threading.Thread(target=test,args=(),name='循环子线程') #初始化一个子线程对象,target是执行的目标函数,args是目标函数的参数,name是子线程的名字
m.start()
t=threading.currentThread() #获取当前线程对象,这里其实是主线程
print t.getName() #打印当前线程名字,其实是主线程名字
Вы можете увидеть результат печати:
循环子线程
MainThread
0
1
2
3
4
5
6
7
8
2. Создается базовым классом потока
import threading,time
class myThread (threading.Thread): #创建一个自定义线程类mythread,继承Thread
def __init__(self,name):
"""
重新init方法
:param name: 线程名
"""
super(myThread, self).__init__(name=name)
# self.lock=lock
print '线程名'+name
def run(self):
"""
重新run方法,这里面写我们的逻辑
:return:
"""
i=0
while i<10:
print i
time.sleep(1)
i=i+1
if __name__=='__main__':
t=myThread('mythread')
t.start()
вывод:
线程名线程
0
1
2
3
4
5
6
7
8
9
синхронизация потоков
Если два потока обращаются к одним и тем же данным одновременно, могут возникнуть непредсказуемые результаты.В настоящее время нам нужно использовать концепцию синхронизации потоков.
Выше мы говорили о модуле потока, уже использующем концепцию блокировки потока, объекты потока Lock и Rlock могут обеспечить простую синхронизацию потока, два объекта имеют методы получения и освобождения, для тех, кому нужно, позволяет только одну операцию данных потока, операция может быть помещена между методом получения и освобождения.
Давайте возьмем пример, нам нужно реализовать 3 потока для одновременного доступа к глобальной переменной и изменить эту переменную:
1. Разблокирован
import threading,time
lock=threading.Lock() #全局的锁对象
temp=0 #我们要多线程访问的全局属性
class myThread (threading.Thread): #创建一个自定义线程类mythread,继承Thread
def __init__(self,name):
"""
重新init方法
:param name: 线程名
"""
super(myThread, self).__init__(name=name)
# self.lock=lock
print '线程名'+name
def run(self):
"""
重新run方法,这里面写我们的逻辑
:return:
"""
global temp,lock
i=0
while i<2: #这里循环两次累加全局变量,目的是增加出错的概率
temp=temp+1 #在子线程中实现对全局变量加1
print self.name+'--temp=='+str(temp)
i=i+1
if __name__=='__main__':
t1=myThread('线程1')
t2=myThread('线程2')
t3=myThread('线程3')
#创建三个线程去执行访问
t1.start()
t2.start()
t3.start()
Результаты выполнения (поскольку программа работает очень быстро, вы можете несколько раз выполнить следующие результаты): Мы можем обнаружить, что поток 1 и поток 2 одновременно обращаются к переменным, что эквивалентно печати
线程名线程1
线程名线程2
线程名线程3
线程1--temp==1线程2--temp==2
线程1--temp==3
线程2--temp==4
线程3--temp==5
线程3--temp==6
2. Ситуация блокировки
import threading,time
lock=threading.Lock() #全局的锁对象
temp=0 #我们要多线程访问的全局属性
class myThread (threading.Thread): #创建一个自定义线程类mythread,继承Thread
def __init__(self,name):
"""
重新init方法
:param name: 线程名
"""
super(myThread, self).__init__(name=name)
# self.lock=lock
print '线程名'+name
def run(self):
"""
重新run方法,这里面写我们的逻辑
:return:
"""
global temp,lock
if lock.acquire(): #这里线程进来访问变量的时候,锁定变量
i = 0
while i < 2: # 这里循环两次累加全局变量,目的是增加出错的概率
temp = temp + 1 # 在子线程中实现对全局变量加1
print self.name + '--temp==' + str(temp)
i = i + 1
lock.release() #访问完毕,释放锁让另外的线程访问
if __name__=='__main__':
t1=myThread('线程1')
t2=myThread('线程2')
t3=myThread('线程3')
#创建三个线程去执行访问
t1.start()
t2.start()
t3.start()
Результаты запуска (сколько бы раз не запускалось, одновременного доступа не будет):
线程名线程1
线程名线程2
线程名线程3
线程1--temp==1
线程1--temp==2
线程2--temp==3
线程2--temp==4
线程3--temp==5
线程3--temp==6
Синхронизация потоков используется во многих местах, таких как захват билетов и лотерейные розыгрыши, Нам необходимо заблокировать некоторые ресурсы, чтобы предотвратить непредсказуемые ситуации во время многопоточного доступа.
очередь потоков
Очередь в python использует модуль Queue, который обеспечивает синхронную безопасную последовательность пар, включая очередь очереди FIFO (первым пришел, первым обслужен), очередь LIFO (последний пришел — первый вышел) LifoQueue и приоритетную очередь PriorityQueue. Все эти очереди реализованы примитивы блокировки, которые можно использовать непосредственно в нескольких потоках. Очереди могут использоваться для связи между потоками
Общие методы в модуле Queue:
- Queue.qsize() возвращает размер очереди
- Queue.empty() возвращает True, если очередь пуста, иначе False
- Queue.full() возвращает True, если очередь заполнена, иначе False
- Queue.full соответствует размеру maxsize
- Queue.get([block[ timeout]]) для получения очереди, время ожидания timeout
- Queue.get_nowait() эквивалентно Queue.get(False)
- Queue.put(item) запись в очередь, время ожидания тайм-аута
- Queue.put_nowait(item) эквивалентен Queue.put(item, False)
- Queue.task_done() После завершения задания функция Queue.task_done() отправляет в очередь сигнал о том, что задание выполнено
- Queue.join() на самом деле означает ожидание, пока очередь не станет пустой, прежде чем делать что-либо еще
пример:
tags=['one','tow','three','four','five','six']
q=Queue.LifoQueue() #先入先出队列
for t in tags:
q.put(t) #将数组数据加入队列
for i in range(6):
print q.get() #取出操作可以放在不同的线程中,不会出现同步的问题
результат:
six
five
four
three
tow
one
Q&A
Многопоточность в этой главе здесь. Мы в основном описываем ее базовое использование. Мы можем разработать другие варианты использования в соответствии с нашей собственной логикой в будущем процессе разработки.