简答来一个demo来演示一下
import threading
import time
def sing():
for i in range(5):
print("正在唱歌")
time.sleep(1)
def dance():
for i in range(5):
print("正在跳舞")
time.sleep(1)
def main():
t1 = threading.Thread(target=sing) # sing是实例对象,而sing()是返回值
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
if __name__ == '__main__':
main()
查看正在运行的线程
import threading
import time
def test1():
for i in range(5):
print("test01---->{}".format(i))
time.sleep(1)
def test2():
for i in range(5):
print("test02---->{}".format(i))
time.sleep(1)
def main():
threading.Thread(target=test1).start()
threading.Thread(target=test2).start()
print(threading.enumerate()) # 查看当前线程个数
# [<_MainThread(MainThread, started 140312615470848)>, <Thread(Thread-1, started 140312584259328)>, <Thread(Thread-2, started 140312575866624)>]
if __name__ == '__main__':
main()
args元祖参数
args指定将来调用函数的时候传递什么参数过去
import threading
import time
def test1(num):
num.append(18)
print(num)
def test2(num):
num.append(55)
print(num)
def main():
threading.Thread(target=test1,args=([11,11],)).start()
threading.Thread(target=test2,args=([10,19],)).start()
if __name__ == '__main__':
main()
互斥锁
# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()
使用互斥锁解决资源竞争的问题
在有可能出现资源竞争的部分,全部用锁套起来
import threading
import time
def test1(num):
# 上锁
mutex.acquire()
num.append(18)
print(num)
# 解锁
mutex.release()
def test2(num):
# 上锁
mutex.acquire()
num.append(55)
print(num)
# 解锁
mutex.release()
def main():
threading.Thread(target=test1,args=([11,11],)).start()
threading.Thread(target=test2,args=([10,19],)).start()
# 创建一个互斥锁
mutex = threading.Lock()
if __name__ == '__main__':
main()
实现多任务udp聊天器
import threading
import socket
def send_data(socket):
while True:
send_data = input("请输入您要发送的数据")
socket.sendto(send_data.encode("utf8"), ("127.0.0.1", 7788))
def revc_data(socket):
while True:
revc_data = socket.recvfrom(1024)
print(revc_data[0].decode("utf8"))
def main():
# 创建stock
udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定port
udp_socket.bind(("127.0.0.1",8899))
# 发送数据
# 接收数据
threading.Thread(target=send_data, args=(udp_socket,)).start()
threading.Thread(target=revc_data, args=(udp_socket,)).start()
if __name__ == '__main__':
main()
使用进程实现多任务
进程的问题就是:浪费资源
import multiprocessing
import time
def test1():
while True:
print("1-----")
time.sleep(1)
def test2():
while True:
print("2----")
time.sleep(1)
def main():
multiprocessing.Process(target=test1).start()
multiprocessing.Process(target=test2).start()
if __name__ == '__main__':
main()
通过Queue队列进程间通信
队列:先进先出
相关方法:
from multiprocessing import Queue
q = Queue # 初始化一个Queue对象,最多可以接收3条put信息
# put放入数据
q.put("xxxx")
# 判断是否满了
q.full()
# 判断锁否空了
q.empyt()
#取数据用get
q.get()
数据下载分析demo演示
import multiprocessing
def download_to_web(q):
# 网络下载数据
data=[11,22,33,44]
for i in data:
q.put(i)
print("下载完成等待提取")
def analysis_data(q):
# 数据处理
lst = []
while True:
print("提取。。。。。")
data = q.get()
lst.append(data)
if q.empty():
break
# 模拟进行数据处理
print("数据处理完成")
def main():
# 创建一个队列
q = multiprocessing.Queue()
# 把队列当作实参进行参数传递
multiprocessing.Process(target=download_to_web,args=(q,)).start()
multiprocessing.Process(target=analysis_data,args=(q,)).start()
if __name__ == '__main__':
main()
进程池Pool
使用场景:
面对大量任务,可以重复利用进程,减少了一个创建和销毁的所消耗的资源
相关方法:
import mutiprocessing import Pool
po = Pool(3)
po.apply_async(要调用的目标,传递给目标的元祖参数)
po.close() # 关闭进程池
po.join() # 阻塞主进程,等待进程池跑完在解堵,运行主进程、结束程序
当主进程与进程池进行通信必须使用:
q = multiprocessing.Manager.Queue()
实现多进程版的copy文件夹
import multiprocessing
import os
def copy_file(q,file_name,folder_name,new_name):
f = open(folder_name+"/"+ file_name,"rb")
content = f.read()
f.close()
f1 = open(new_name+"/"+file_name,"wb")
f1.write(content)
f1.close()
# 拷贝完成往队列里放入一个信息
q.put(file_name)
def main():
# 获取用户要copy的文件夹名称
folder_name = input("请输入您要copy文件夹的名称:")
# 创建一个新的文件夹
try:
new_name = folder_name+"附件"
os.mkdir(new_name)
except:
pass
# 获取文件夹中所有的待copy的文件名字 os.listdir("路径")
file_names=os.listdir(folder_name)
# 复制原文件夹中的文件,到新文件夹中去
po = multiprocessing.Pool(3)
# 创建一个队列q
q = multiprocessing.Manager().Queue()
for file_name in file_names:
po.apply_async(copy_file,args=(q,file_name,folder_name,new_name))
po.close()
#po.join()
# 进程间通信
all_file_name = len(file_names)
copy_num = 0
while True:
file_name = q.get()
print("已经完成copy:{}".format(file_name))
copy_num +=1
print("拷贝进度{}{}".format(copy_num*100/all_file_name,"%"))
if copy_num >=all_file_name:
print("拷贝完成亲!!!")
break
if __name__ == '__main__':
main()
迭代器
我们定义一个类Classmate
class Classmate(object):
def __init__(self):
self.names = []
def add(self,name):
self.names.append(name)
# 实例化一下
classmate = Classmate()
# 调用一下add
classmate.add("老外")
classmate.add("张三")
classmate.add("李四")
# 看一下能否迭代
for name in classmate:
print(name) # TypeError: 'Classmate' object is not iterable
那么我们怎么能让一个类可以迭代那?
一个类有__iter__方法叫可迭代
当有__iter__和__next__方法后叫迭代器
每for一次就调用一次__next__返回什么for出来就是什么
class Classmate(object):
def __init__(self):
self.names = []
def add(self,name):
self.names.append(name)
self.current_num = 0
def __iter__(self):
"""
如果想要一个对象称之为可迭代对象,即可以使用for,
那么必须实现__iter__方法
"""
return self
def __next__(self):
if self.current_num<len(self.names):
ret = self.names[self.current_num]
self.current_num+=1
return ret
else:
raise StopIteration # 此异常是专门用于迭代器退出的
# 实例化一下
classmate = Classmate()
# 调用一下add
classmate.add("老外")
classmate.add("张三")
classmate.add("李四")
# 看一下能否迭代
for name in classmate:
print(name)
迭代器的使用场景是什么?会迭代器和不会迭代器有什么区别?
当有一个很大的列表数据,当我们不会迭代器,就要把整个数据集展示出来,占用极大的内存
而迭代器,他不是数据集,而是一个可以产生数据集的方式,占用极小内存。
使用迭代器实现斐伯纳耶数列
class Fibonacci(object):
def __init__(self,all_num):
self.all_num = all_num
self.current_num = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
lst = []
if self.current_num<self.all_num:
for i in range(self.all_num):
lst.append(self.a)
self.a,self.b = self.b,self.a+self.b
self.current_num+=1
return lst
else:
raise StopIteration
fibo = Fibonacci(10)
for i in fibo:
print(i)
生成器:是迭代器特殊版本
生成器创建方式一、小括号()
# []返回的是一个列表
nums = [x*2 for x in range(10)] # [0,2,4,6,8,12,14,18]
#()返回的是一个生成器,优点:占用空间小,他产生的不是数据集,而是生成数据集的方法
nums =(x*2 for x in range(10) # <generator object <genexpr> at 0x7f04e12d9690>
生成器创建方式二、函数末尾添加yield就是一个生成器
如果一个函数中yield语句,那么这个就不是函数,而是一个生成器模板
def create_num(all_num):
a, b = 0,1
current_num =0
while current_num<all_num:
yield a
a, b = b, a+b
current_num+=1
for i in create_num(10):
print(i)
启动生成器
方法一:next(放入生成器)
第一种方法不能往生成器内传入参数
方法二:生成器.send()
第二种方法是可以实现往生成器内传入参数,此参数代替yield的值
生成器的主要用途:实现多任务
import time
def task_1():
while True:
print("---1---")
time.sleep(0.1)
yield
def task_2():
while True:
print("---2---")
time.sleep(0.1)
yield
def main():
t1 = task_1()
t2 = task_2()
while True:
next(t1)
next(t2)
if __name__ == '__main__':
main()
gevent协程完成多任务
安装gevent
pip3 insatll gevent
import gevent
import time
from gevent import monkey #补丁会检查代码,把所有延时内容都会替换成gevent的延时
monkey.patch_all() # 打补丁
def test1(n):
for i in range(n):
print("---A---")
time.sleep(0.5) # 碰到延时gevent会进行切换
def test2(n):
for i in range(n):
print("---B---")
time.sleep(0.5) # 碰到延时gevent会进行切换
gevent.joinall([gevent.spawn(test1,5),
gevent.spawn(test2,5)
])
协程是一个程序等待时,我们切换其他程序进行
使用协程实现图片下载案例
import urllib.request
import gevent
from gevent import monkey
import random
monkey.patch_all()
def downloader(img_url):
req = urllib.request.urlopen(img_url)
img_content = req.read()
with open(str(random.randint(1,80))+"1.jpg", "wb")as f:
f.write(img_content)
def main():
gevent.joinall([gevent.spawn(downloader,"图片url"),
gevent.spawn(downloader,"图片url")])
if __name__ == '__main__':
main()
协程、进程、线程对比
进程占用资源大,效率低
线程资源耗费小,效率一般
进程线程是属于并行
而,协程是利用了线程在执行任务时等待的期间去执行其他的任务,效率最高,属性并发