多线程的知识归类
1.线程通信强化
import threading
import time
def goevent():
e = threading.Event() # 事件
def go():
for i in range(10):
e.wait() # 等待事件,线程卡顿,等待set消息,只调用一次
e.clear() # 重置线程等待
print("go",i)
threading.Thread(target=go).start() # 创建一个线程
return e
t = goevent()
for i in range(5):
time.sleep(i)
t.set()
2.condition线程通讯与事件
线程1和线程2顺序交换使用
import threading
import time
def go1():
with cond:
for i in range(10):
time.sleep(1)
print(threading.current_thread().name, i)
if i == 5:
cond.wait() # 等待,只有在其他相同线程条件变量唤醒时才继续执行
print("hahahha")
'''
wait()
此方法释放底层的锁,然后阻塞,直到它
通过notify()或notify_all()调用唤醒相同的条件
在另一个线程中变量,或直到发生可选的超时。一旦
唤醒或超时,它重新获得锁定并返回。
'''
def go2():
with cond: # 使用条件变量
for i in range(10):
time.sleep(1)
print(threading.current_thread().name, i)
cond.notify() # 通知唤醒其他线程
'''
notify()
在这种情况下唤醒一个或多个线程,如果有的话。
如果调用线程没有获得这个方法的锁
称为,引发了一个RuntimeError。
这个方法至多唤醒n个等待条件的线程
变量; 如果没有线程正在等待,那么这是一个无操作。
'''
cond = threading.Condition() # 线程条件变量
threading.Thread(target=go1).start()
threading.Thread(target=go2).start()
'''
代码逻辑
cond只有一个,线程1线锁定cond,当线程1跑到i==5的时候
此时进入condition等待,将资源释放出来,
这时候线程2进入,一口气全部跑完i,跑到最后以cond.notifly通知
将资源再放出来,此时线程1重新锁定
'''
3.线程调度
**一个线程完了接下一个线程,一人一下,wait()后的代码不会再运行,等notify进来会运行
import threading
import time
def go1():
with cond:
for i in range(0, 10, 2):
time.sleep(1)
print(threading.current_thread().name, i)
cond.wait()
# print("hahah")
cond.notify()
def go2():
with cond:
for i in range(1, 10, 2):
time.sleep(1)
print(threading.current_thread().name, i)
cond.notify()
cond.wait()
cond = threading.Condition() # 线程条件变量
threading.Thread(target=go1).start()
threading.Thread(target=go2).start()
'''
逻辑:
首先明确wait()调用后下面的程序是不会运行的,
首先线程1线绑定cond,打印出0后,线程1进入等待(注意此时线程2并没有绑定),线程2绑定cond,打印出1后
notify给线程1唤醒wait(),(此时才打印出"haha"),同时线程2的wait激活进入等待,同时1打印出2,并唤醒线程2如此循环
'''
4.生产者消费者模式
# # 在队列中,有多个生产者将商品放入队列,同时又多个消费者在队列的另一头获取商品,一般
# # 情况下会产生线程冲突,但是python已经将此处理好了,也就是说在将商品放入队列的过程中无需考虑线程冲突
# import threading
# import queue
# import time
# import random
# # 生产
# class CreatorThread(threading.Thread):
# def __init__(self, index, myqueue):
# threading.Thread.__init__(self)
# self.index = index # 索引
# self.myqueue = myqueue # 队列
# def run(self):
# while True:
# time.sleep(3)
# num = random.randint(1, 1000000)
# self.myqueue.put("in put 生产者" + str(self.index) + str(num))
# print("in put 生产者", str(self.index), str(num))
# # self.myqueue.task_done() # 完成任务
# # 消费
# class BuyerThread(threading.Thread):
# def __init__(self, index, myqueue):
# threading.Thread.__init__(self)
# self.index = index # 索引
# self.myqueue = myqueue # 队列
# def run(self):
# while True:
# time.sleep(1)
# item = self.myqueue.get() # 获取数据,拿不到一直等待
# if item is not None:
# print("消费者:" , item,'\n')
#
#
# myqueue = queue.Queue(10) # 0代表无限,内存有多大装多大,
# for i in range(3): # 3个生产者同时放入
# CreatorThread(i, myqueue).start() # 创建生产者
#
# for j in range(8):# 8个消费者同时获取,最多只能获取到生产者生产的
# BuyerThread(j, myqueue).start() # 创建消费者
import threading
import time
import queue
q = queue.Queue(maxsize=10)
def producer(name): # 生产者
count = 1
while True:
q.put("骨头%s" % count)
print("生产了骨头", count)
count += 1
time.sleep(0.5)
def consumer(name): # 消费者
while True:
print("[%s]取到[%s]并且吃了它..." % (name, q.get()))
time.sleep(1)
p = threading.Thread(target=producer, args=("Tim",))
c1 = threading.Thread(target=consumer, args=("King",))
c2 = threading.Thread(target=consumer, args=("Wang2",))
c3 = threading.Thread(target=consumer, args=("Wang3",))
c4 = threading.Thread(target=consumer, args=("Wang4",))
c5 = threading.Thread(target=consumer, args=("Wang5",))
p.start()
c1.start()
c2.start()
c3.start()
c4.start()
c5.start()
5.线程池
import threadpool # 需要安装
import time
def show(name):
print('hello', name)
namelist = ["A", "B", "C", "D"]
start = time.time()
pool = threadpool.ThreadPool(7) # 线程池最大数,貌似还要远大于列表长度
requests = threadpool.makeRequests(show, namelist) # 设置参数,函数,参数列表
print(requests)
print()
for req in requests:
pool.putRequest(req) # 压入线程池开始执行
end = time.time()
print(end - start)
6.定时线程框架
import time
import threading
import os
'''
def show():
os.system("say hello")
mythreading = threading.Timer(3, show).start() # 延时3秒启动show函数,只启动一次
num = 0
while True:
print('第', num, "秒")
time.sleep(1)
num += 1
'''
def show():
while True:
time.sleep(3)
print("say hello")
mythreading = threading.Timer(3, show).start() # 延时3秒启动show函数,只启动一次,不阻塞主线程
num = 0
while True:
print('第', num, "秒")
time.sleep(1)
num += 1
# mythreading.cancel() # 因为cancel取消了线程的执行,所以fun()函数不会被执行
6.1定时线程举例
import threading
def A(name):
print(name)
t=threading.Timer(5,function=A,args=("ljr"))
t.start()
t.join()
print("Over")
7.with的作用
相当于锁lock
import threading
num = 0 # 全局变量可以在线程之间传递
mutex = threading.Lock() # 创建一个锁,threading.Lock()是一个类
class Myhtread(threading.Thread):
def run(self):
global num
with mutex:
for i in range(1000000): # 数字小的时候还是不会产生线程冲突的
num += 1
print(num)
mythread = []
for i in range(5):
t = Myhtread()
t.start()
mythread.append(t)
for thread in mythread:
thread.join() # 或者直接将thread.join()加入for i in range(5),也能解决线程冲突,但是貌似就变成单线程了
print("game over")
'''
with 作用自动打开和释放,python3新功能
'''
8.TLS
# 线程独立
import threading
import time
data = threading.local() # 每个线程私有独立储存空间
t1 = lambda x: x + 1
t2 = lambda x: x + "1"
def printdata(func, x):
data.x = x # data = threading.local() 本质上是一个类,此处为动态绑定
print(id(data.x)) # 不同地址互相独立data.x 在每个线程中是独立的
for i in range(5):
data.x = func(data.x)
print(threading.current_thread().name, data.x)
threading.Thread(target=printdata, args=(t1, 1)).start()
threading.Thread(target=printdata, args=(t2, "1")).start()
9.后台线程
import threading
import time
# import win32api # 引用系统函数
class Mythread(threading.Thread): # 继承threading.Thread
def run(self): # run重写,
# win32api.MessageBox(0, "你的账户很危险", "来自支付宝的问候", 6)
print('hahah')
mythread = [] # 集合list
for i in range(5):
t = Mythread() # 初始化
t.setDaemon(True) #后台线程,主线程不等后台线程
t.start()
mythread.append(t) # 加入线程集合
# threading.Thread默认是前台进程,主线程必须等前台。
print("game over")
10.正则
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
附:最常用的正则匹配符号表
11.正则举例
爬取89ip网站中的内容
import requests
import re
headers={
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36'
}
for i in range(1,11):
url="http://www.89ip.cn/index"+str(i)+".html"
response = requests.get(url,headers=headers)
html=response.text
#print(html)
res=re.findall("<td>\n.*\t(.*?)\t\t</td>",html)
print(res)