8.Python基础学习笔记day8-正则表达式、网络编程、进程与线程
8.Python基础学习笔记day8-正则表达式、网络编程、进程与线程
一、正则表达式
'''
1、
[1,2,3,4]中任意取3个元素排列:
A43 = 4x3x2 = 24itertools.permutations(list1,r)
参数一:可迭代对象
参数二:取元素的个数
注意:可迭代对象中的元素不能重复[与顺序有关]
功能:返回从可迭代对象中取出r个元素的排列,以迭代器的方式返回。[1,2,3,4]中任意取3个元素组合:
C43=4x3x2/(3x2x1)= 42、itertools.combinations(iter2,r)参数一:可迭代对象参数二:取元素的个数功能:从iter2中取r个的元素的组合注意:iter2中不能重复。3、排列组合
itertools.product(iter2,repeat=n)参数一:可迭代对象参数二:取元素的位数功能:n位中的每一位都可以从可迭代对象取
'''
import itertoolslist1 = [1,2,3,4]
res = itertools.permutations(list1,3)
print(len(list(res))) # 24res2 = itertools.combinations(list1,3)
print(list(res2)) # [(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]res3 = itertools.product("1234567890",repeat=6)_ _ _ _ _ _print(len(list(res3))) # 1000000'''
re.findall(pattren,string)
参数一:正则表达式
参数二:被正则的字符串
功能:对string进行正则匹配,将匹配到的结果作为列表返回
'''
'''
相关正则函数标志位
flags:标志位,用于控制正则表达式的匹配方式,值如下
re.I 忽略大小写 ---常用
re.L 做本地户识别
re.M 多行匹配,影响^和$ ---常用
re.S 是.匹配包括换行符在内的所有字符
re.U 根据Unicode字符集解析字符,影响\w \W \b \B
re.X 使我们以更灵活的格式理解正则表达式
''''''
4、元字符:
. 匹配除换行符以外的任意字符
[0123456789] []是字符集合,表示匹配方括号中所包含的任意一个字符
[a-z] 匹配任意小写字母
[A-Z] 匹配任意大写字母
[0-9] 匹配任意数字,类似[0123456789]
[0-9a-zA-Z] 匹配任意的数字和字母
[0-9a-zA-Z_] 匹配任意的数字、字母和下划线
[^0-9] 匹配所有的非数字字符
\d 匹配数字,效果同[0-9]
\D 匹配非数字字符,效果同[^0-9]
\w 匹配数字,字母和下划线,效果同[0-9a-zA-Z_]
\W 匹配非数字,字母和下划线,效果同[^0-9a-zA-Z_]
\s 匹配任意的空白符(空格,换行,回车,换页,制表),效果同[ \f\n\r\t]
\S 匹配任意的非空白符,效果同[^ \f\n\r\t]
'''
string = "you are very good,\r\n12 23 3you are very great!!!"
print(re.findall("you",string)) # ['you', 'you']
print(re.findall(r"[you]",string)) # ['y', 'o', 'u', 'y', 'o', 'o', 'y', 'o', 'u', 'y']
print(re.findall(r".",string)) #
print(re.findall(r"[0-9]",string)) # ['1', '2', '2', '3', '3']
print(re.findall(r"\d",string)) # ['1', '2', '2', '3', '3']
print(re.findall(r"[^0-9]",string))
print(re.findall(r"\D",string))print(re.findall(r"[0-9a-zA-Z_]",string))
print(re.findall(r"\w",string))
print(re.findall(r"[^0-9a-zA-Z_]",string))
print(re.findall(r"\W",string))print(re.findall(r"\s",string))
print(re.findall(r"[ \n\r\t\f]",string))
print(re.findall(r"[^ \n\r\t\f]",string))
print(re.findall(r"\S",string))'''
5、锚字符(边界字符):
^ 行首匹配,和在[]里的^不是一个意思
$ 行尾匹配\A 匹配字符串开始,它和^的区别是,\A只匹配整个字符串的开头,即使在re.M模式下也不会匹配它行的行首
\Z 匹配字符串结束,它和$的区别是,\Z只匹配整个字符串的结束,即使在re.M模式下也不会匹配它行的行尾\b 匹配一个单词的边界,也就是值单词和空格间的位置'er\b'可以匹配never,不能匹配nerve
\B 匹配非单词边界
'''
str1 = "you a very good\nyou a very good"
str2 = " you a very good"
str3 = "good good"
print(re.findall(r"^you",str1,flags=re.M)) # ['you', 'you']
print(re.findall(r"\Ayou",str1,flags=re.M)) # ['you']
print(re.findall(r"good$",str1,flags=re.M)) # ['good', 'good']
print(re.findall(r"good\Z",str1,flags=re.M)) # ['good']
print(re.findall(r"^you",str2)) # []
print(re.findall(r"^good$",str2)) # []
print(re.findall(r"^good$",str3)) # []print(re.findall(r"er\b","never erver")) # ['er', 'er']
print(re.findall(r"\ber","never erver")) # ['er']
print(re.findall(r"\ber\b","never er erver")) # ['er']
print(re.findall(r"er\B","never er erver")) # ['er']
print(re.findall(r"\Ber","never er erver")) # ['er', 'er']'''
6、匹配多个字符
说明:下方的x、y、z均为假设的普通字符,n、m(非负整数),不是正则表达式的元字符
(xyz) 匹配小括号内的xyz(作为一个整体去匹配)
x? 匹配0个或者1个x
x* 匹配0个或者任意多个x(.* 表示匹配0个或者任意多个字符(换行符除外))
x+ 匹配至少一个x
x{n} 匹配确定的n个x(n是一个非负整数)
x{n,} 匹配至少n个x
x{n,m} 匹配至少n个最多m个x。注意:n <= m
x|y |表示或,匹配的是x或y
'''
str1 = "you are very good you are a great man"
str2 = "youareverygoodyou are a good man"print(re.findall(r"[a-z]?",str1))
print(re.findall(r"[a-z]*",str2)) # ['youareverygoodyou', '', 'are', '', 'a', '', 'good', '', 'man', '']
print(re.findall(r"[a-z]+",str1)) # ['you', 'are', 'very', 'good', 'you', 'are', 'a', 'great', 'man']
print(re.findall(r"[a-z]{3}",str1)) # ['you', 'are', 'ver', 'goo', 'you', 'are', 'gre', 'man']
print(re.findall(r"[a-z]{3}",str2)) # ['you', 'are', 'ver', 'ygo', 'ody', 'are', 'goo', 'man']
print(re.findall(r"[a-z]{3,}",str2)) # ['youareverygoodyou', 'are', 'good', 'man']
print(re.findall(r"[a-z]{3,4}",str2)) # ['youa', 'reve', 'rygo', 'odyo', 'are', 'good', 'man']
print(re.findall(r"good|great",str1)) # ['good', 'great']'''
需求写一个正则电话的正则:
电话号码以
1开头
长度11位
全部数字
'''
print("*"*50)
print(re.findall(r"^1\d{10}$","123948293403794"))
print(re.findall(r"^1\d{10}$","12394829340"))
print(re.findall(r"^1\d{10}$","1239482934a"))
print(re.findall(r"^1\d{10}$","1239482934"))'''
邮箱地址正则:
5-11位数字或者小写字母
@qq.com/@163.com/@sina.cn
'''
print("*"*50)
print(re.match(r"^[0-9a-z]{5,11}(@qq\.com|@163\.com|@sina\.cn)$","11222@qq.cn"))
print(re.match(r"^[0-9a-z]{5,11}(@qq\.com|@163\.com|@sina\.cn)$","11222@qq.com"))
'''
需求:
str1 = "you are a good man,you are a nice man ,you are a great man,you are a..."提取:you...man
'''
str1 = "you are a good man,you are a nice man ,you are a great man,you are a..."print(re.findall(r"you.*?man",str1))'''
.*? 经常一起连用,.代表任意字符 *尽可能多的匹配,?对贪婪匹配的限制
'''
'''
需求:
str2 ="/* part1 *//* part2 *//* part3 */"提取 /*...*/
'''
str2 ="/* part1 *//* part2 *//* part3 */"
print(re.findall(r"/\*(.*?)\*/",str2))'''
re.split(pattern,string,maxsplit,flags)
功能:以指定的正则对string进行切片,并且将切片后的结果作为列表返回。
maxsplit:指定最大切片次数,若不指定,全部切片
'''
str1 = "zhangsan is a good man"
print(str1.split(" ")) # ['zhangsan', '', '', '', 'is', 'a', 'good', 'man']
print(re.split(r" +", str1)) # ['zhangsan', 'is', 'a', 'good', 'man']'''
re.finditer函数
原型:finditer(pattern, string, flags=0)
参数:
patter: 匹配的正则表达式
string: 要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式
功能:与findall类似,扫描整个字符串,返回的是一个迭代器
'''
print(list(re.finditer("hello","ohahelloha"))) # [<_sre.SRE_Match object; span=(3, 8), match='hello'>]'''
re.sub(pattern,repl,string,count)
功能:将匹配到的字符以指定的repl进行替换并且返回替换后的结果
count:指定替换次数,若不指定则默认全部替换
'''
print(re.sub(r"\d+"," ","dd1w3sd2333adfeeft344dfffg3df",count=3)) # ['dd', 'w', 'sd', 'adfeeft', 'dfffg', 'df']'''
re.match(pattern,string,flags)
参数一:正则表达
参数二:string
参数三:标志位
功能:对string从字符串开始进行匹配,若匹配的上则返回匹配成功的对象,若匹配不上则返回None
注意:这并不是一个完全匹配,若匹配成功之后,string有剩余仍然匹配成功,若要完全匹配,可以在正则
的末尾添加$即可
'''
print(re.match("hello","hellohaha"))'''
re.search(pattern,string,flags)
参数一:正则表达式
参数二:字符串
参数三:标志位
功能:以指定的正则格式在string进行查找若找到则直接返回第一匹配成功的对象,不再继续匹配。
若找不到返回None
'''
print(re.search("hello","ohahellha"))'''re.compile(pattern,flags)参数一:正则表达式参数二:标志位功能:将正则表达式编译成一个正则对象然后返回。调用的时候调用正则对象即可。
'''
# print(re.match(r"^[0-9a-z]{5,11}(@qq\.com|@163\.com|@sina\.cn)$","11222@qq.cn"))
comobj = re.compile(r"^[0-9a-z]{5,11}(@qq\.com|@163\.com|@sina\.cn)$")
comobj.findall()
二、网络编程
'''
1、TCP网络编程
服务端、客户端、套接字socket、OSI七层模型、三次握手、四次挥手套接字:源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字。其用于标识客户端请求的服务器和服务常用的TCP/IP协议的3种套接字类型如下所示。
流式套接字(SOCK_STREAM):
流式套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流式套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(The Transmission Control Protocol)协议。数据报套接字(SOCK_DGRAM):
数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP(User Datagram Protocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。原始套接字(SOCK_RAW):
原始套接字(SOCKET_RAW)允许对较低层次的协议直接访问,比如IP、 ICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW原始套接字与标准套接字(标准套接字指的是前面介绍的流式套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流式套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字
'''
# 导入socket
import socket
'''
(1)#创建socket对象
参数一:指定的ip协议 ipv4协议
参数二:指定的tcp协议
'''
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)'''
(2)#绑定地址和端口
address地址,以元组的形式传递
域名/ip地址 端口号
网页的端口 80
STMP服务端口 25
'''
sock.bind(("10.36.151.41",9090))'''
(3)设置最大连接数
'''
sock.listen(6)'''
(4)接收客户端的链接
accept() -> (socket object, address info)
返回一个元组,含socket对象(套接字),和远程客户端地址address
'''
clientSocket,clientAddress = sock.accept()'''clientSocket:<socket.socket fd=260, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8081), raddr=('127.0.0.1', 61642)>clientAddress:('127.0.0.1', 61642)''''''
(5)获取已连接的客户端发送的数据,返回数据类型是二进制的
'''
clientSocket.recv(1024).en_code("utf-8")'''
(6)通过套接字向远程客户端发送数据,函数要求所发送数据一定要编码成二进制格式,
返回成功发送数据的字节数(中文占3个字节)
def send(self, data: bytes, flags: int = ...) -> int: ...
'''
sendData = input("输入返回给客户端的数据")
clientSocket.send(sendData.encode("utf-8"))
clientSocket.close() # 关闭连接
'''
(7)# 客户端使用建立连接
# 参数:是一个元组,第一个元素为要连接的服务器的IP地址,第二个参数为端口
'''
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 获取套接字
client.connect(("127.0.0.1", 8081)) # 连接远程地址,相当于在套接字加入远程地址
print(client)
'''
(8)
<socket.socket fd=276, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 62356), raddr=('127.0.0.1', 8081)>fd: fd 是(file descriptor),这种一般是BSD Socket的用法,用在Unix/Linux系统上。在Unix/Linux系统下,一个socket句柄,可以看做是一个文件,在socket上收发数据,相当于对一个文件进行读写,所以一个socket句柄,通常也用表示文件句柄的fd来表示。family:AF_INET(ADDRESS FAMILY Internet 网络地址族[默认ipv4])、AF_INET6(ipv6)(PF_INET,在windows下与AF_INET意义一样)type:套接字类型
laddr(localaddress):本地地址
raddr(remoteaddress):远程地址
''' '''
整体代码
'''
# 服务器端:
import socket
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.bind(("127.0.0.1",9090))
clientSocket,clientAddress = sock.accept()
while True:data = clientSocket.recv(1024)print("客户端说:" + data.decode("utf-8"))sendData = input("输入返回给客户端的数据")print(clientSocket.send(sendData.encode("utf-8")))clientSocket.close() # 关闭连接
# 客户端
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 8081))
while True:data = input("请输入给服务器发送的数据")client.send(data.encode("utf-8"))# 等待接收数据info = client.recv(1024)print("服务器说:", info.decode("utf-8"))'''
2、udp编程
无连接的服务、不可靠传输
直接上代码:
'''
# 服务端
import socketudpServer = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 获取udp协议套接字
udpServer.bind(('127.0.0.1', 8900)) # 绑定服务器地址
while True:data, addr = udpServer.recvfrom(1024) # 接受任意客户端发过来的udp请求,返回客户端内容,地址端口(元组)【可以另开线程接受信息】print("客户端说:", data.decode("utf-8"))udpServer.sendto("你好吗".encode("utf-8"),addr)# 客户端
import socketclient = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 获取udp协议套接字
while True:data = input("请输入数据")client.sendto(data.encode("utf-8"), ('127.0.0.1', 8900)) # 发送内容到指定ip地址端口fromsdata, address = client.recv(1024) # 【可以另开线程接受信息】print(fromsdata.encode("utf-8"))
三、线程
'''
线程
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。GIL:
GIL是Python解释器(Cpython)引入的概念,在JPython、PyPy中没有GIL。GIL并不是Python的语言缺陷。GIL定义
GIL,the Global Interpreter Lock,直译为“全局解释锁”GIL存在原因
CPython在执行多线程的时候并不是线程安全的,为了保证线程间数据的一致性和状态同步的完整性。GIL的弊端
- GIL对计算密集型的程序会产生影响。因为计算密集型的程序,需要占用系统资源。GIL的存在,相当于始终在进行单线程运算,这样自然就慢了。
- IO密集型影响不大的原因在于,IO,input/output,这两个词就表明程序的瓶颈在于输入所耗费的时间,线程大部分时间在等待,所以它们是多个一起等(多线程)还是单个等(单线程)无所谓的。这就好比,你在公交站等公交时,你们竖成一排等公交(单线程)还是沿着马路一字排开等(多线程)是无所谓的。公交车(即input,即输入的资源)没来,哪种方式都是瞎折腾。如何解决1、重写python编译器(官方cpython)如使用:PyPy解释器2、调用C语言的链接库异步:不按照顺序执行,并行执行。ps:可以理解为在不同的线程执行
串行:类似于同步
并行:类似于异步执行【执行任务的数量小于或者等于cpu的数量】
并发:任务的数量大于cpu的数量
同步:按顺序执行代码 ps:可以理解成在同一个线程中执行''''''
1、创建线程的方法1
_thread
''''''创建守护线程'''
import _thread
import time
import threadingdef func(msg):print(msg)# 获取当前正在执行的线程print(threading.current_thread().name)def create_thead():'''参数一:在子线程中执行的函数参数二:子线程执行函数的时候需要的参数,传递参数的时候一定要以元组的方式传参守护线程:无论守护是否执行结束,只要主线程结束,守护线程都会自动结束'''_thread.start_new_thread(func, ("hello world",))if __name__ == '__main__':create_thead()# print("main",threading.current_thread())time.sleep(1)'''
2、创建线程的方法2
threading
'''
import threading
import timedef func(msg):print(msg)print(threading.current_thread().name)if __name__ == '__main__':t = threading.Thread(target=func, args=("hello world",))t.start()print("main",threading.current_thread().name)# time.sleep(5)'''
3、创建线程的方法3
面向对象
'''
import threading
class MyThread(threading.Thread):def __init__(self,msg):super().__init__()self.msg = msg'''若通过继承来创建线程,那么我们必须要重写一个函数,这个函数就是run函数在此函数中我们可以写在子线线程中要执行的程序。此函数不需要我们自己手动调用当我们启动线程的时候,会自动调用此方法。'''def run(self):print("哈哈")print(self.msg)print(threading.current_thread().name)if __name__ == '__main__':t = MyThread("hello world")t.start()'''
4、线程常用函数
''' '''target:线程执行函数args:函数需要的参数,必须以元组的方式传参name:指定子线程的名字daemon:设置是否为守护线程,默认为False,若为守护线程则为True'''t = threading.Thread(target=func,args=("hello",),name="helloname",daemon=False)t.isAlive() # 功能:判断线程是否还活着t.getName() # 获取线程的名字t.setName() # 设置线程的名字t.start() # 开启线程,线程准备就绪t.isDaemon() # 判断某个线程是否为后台线程t.join([timeout]): # 阻塞当前上下文环境的线程,直到调用此方法的线程终止或到达指定的timeout'''
5、线程冲突
''' import threading
def func():global num'''cpu分配的时间片不足以完成一百万次的加法运算,因此,数据还没有被保存,就被其他的线程打断了。'''for x in range(1000000):num += 1if __name__ == '__main__':num = 0tlist = []for x in range(5):t = threading.Thread(target=func)t.start()tlist.append(t)for t in tlist:t.join()print(num)'''
6、解决线程冲突
线程锁
'''
import threadinglock = threading.Lock()
'''
# lock.acquire() #上锁
# lock.release() #释放锁
lock = threading.Lock()
使用 with lock
with内部实现了enter()和exit()执行语句之前调用enter方法,退出的时候调用exit
'''def func():with lock:global numfor x in range(1000000):num += 1# lock.acquire() #上锁# lock.release() #释放锁if __name__ == '__main__':num = 0tlist = []for x in range(5):t = threading.Thread(target=func)t.start()tlist.append(t)for t in tlist:t.join()print(num)'''
7、线程锁的问题:
死锁
定义:是指一个资源多次调用,而多次调用方都未能释放该资源就会造成一种互相等待的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或者系统产生了死锁。若存在两个线程:线程A 与线程B
若线程A与线程B都 需要资源1与资源2才能执行
现在线程A拿到了资源1,线程B拿到了资源2,此时就构成了死锁。
若要解决死锁的问题,则此时我们需要使用递归锁。
'''
'''
使用递归锁来解决死锁的问题。
递归锁的实现原理:
在递归锁中不但存在lock还存在counter计数,每当acquire()一次锁,counter计数就进行
加1处理,每当release() 一次锁,counter计数减1处理,直到counter计数为0的情况下
所有线程重新去抢占资源。
'''import threading
import time# A = threading.Lock()
# B = threading.Lock()
# 创建递归锁
rlock = threading.RLock()
class MyThread(threading.Thread):def fun1(self):rlock.acquire()print(self.name,"gotA",time.ctime())time.sleep(2)rlock.acquire()print(self.name,"gotB",time.ctime())time.sleep(1)rlock.release()rlock.release()def func2(self):rlock.acquire()print(self.name,"gotB",time.ctime())time.sleep(2)rlock.acquire()print(self.name,"gotA",time.ctime())time.sleep(1)rlock.release()rlock.release()def run(self):self.fun1()self.func2()if __name__ == '__main__':L = []for i in range(5):t = MyThread()t.start()L.append(t)for i in L:i.join()print("over")'''
8、信号量的实现方式:
解决,限制同一时间执行线程的个数:
在内部有一个counter计数器,每当我们 s.acquire()一次,计数器就进行减1处理
每当 s.release()一次,计数器就进行加1处理,当计数器为0的时候其他线程的就处于
等待的状态counter的值就是同一时间可以开启线程的个数
建议使用with
'''s = threading.Semaphore(5)def func():# s.acquire()with s:time.sleep(1)print(threading.current_thread().name)print(time.ctime())# s.release()if __name__ == '__main__':for x in range(40):t = threading.Thread(target=func)t.start()
四、协程及进程
'''
协程:
协程,又称微线程,纤程,协程其实可以认为是比线程更小的执行单元,为啥说他是一个执行单元,因为他自带cpu上下文(地址),这样只要在合适的时机,我们可以把一个协程切换到另一个协程,只要这个过程中保存或者恢复cpu上下文,那么这个程序还是可以运行的。通俗的理解:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另一个函数中执行,注意不是通过调用函数的方式做到的,并且切换的次数以及什么时候再切换到原来的函数中都是由开发者自己确定的。协程与线程的差异:协程的特点在一个线程内部执行,与多线程相比,协程有什么优点?1.最大的优势就是协程有极高的执行效率,因为子程序切换不是线程切换而是程序自身控制,因此,没有线程切换的开销,和多线程比,线程的数量越多,协程的性能就会越明显2.第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。因为协程是一个线程执行,那么怎么利用多核cpu呢?最简单的方式就是多进程+协程,既充分利用多核,又能充分发挥协程的高效性,可获得极高的性能。协程的缺点:它不能同时将cpu的多核用上,只能使用一个核;python对协程的支持是通过generator实现的在generator中,我们不但能够通过for循环作用,我们还可以不断调用next()函数,获取由yield语句返回的下一个值
''''''
yield关键字的作用:能过多次进入、多次返回,能够暂停函数体中代码的执行在python的函数(function)定义中,只要出现了yield表达式(Yield expression),那么事实上定义的是一个generator function, 调用这个generator function返回值是一个generator例如:使用yield生成斐波那契数列
'''
from collections import Iteratordef func(n):a = 1b = 1for x in range(1,n+1):if x == 1 or x == 2:yield aelse:a,b = a+b,ayield aif __name__ == '__main__': g = func(10) print(isinstance(g, Iterator)) # True 判断是否为迭代器for x in g:print(x, end=" ") # 1 1 2 3 5 8 13 21 34 55 '''
协程的实现方式1:
yield
'''
import timedef func():while True:print("====func===")yieldtime.sleep(1)def func2(func):while True:print("====func2====")next(func)time.sleep(1)if __name__ == '__main__':#返回了一个生成器对象f = func() # 有yield,不执行里面的内容,返回生成器对象func2(f)'''
===func2===
====func1====
===func2===
====func1====
===func2===
...
''' '''
协程的实现方式2:
使用greenlet来实现协程
'''
from greenlet import greenlet
import timedef fun1():print("协程1...")time.sleep(3)g2.switch() #切换到协程g2print("节日快乐。。。")def fun2():print("协程2...")time.sleep(3)g1.switch() #切换到协程g1if __name__ == '__main__':# greenlet(func) 创建协程g1 = greenlet(fun1)print(g1)g2 = greenlet(fun2)# 切换并且执行g1.switch()'''
协程1...
协程2...
节日快乐。。。
''' '''
协程的实现方式3:
使用gevent与monkey实现协程
'''
from gevent import monkey;monkey.patch_all()#导入猴子补丁#可以实现协程的自动切换
import requests
import gevent
import threading
import timeheaders = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'}def get_data(url):response = requests.get(url,headers=headers)print(url,"response")time.sleep(3)if __name__ == '__main__':#协程爬取数据t1 = time.time()url_list = ['http://www.baidu.com','http://www.qq.com','http://www.ifeng.com','http://www.sina.com.cn','http://www.taobao.com',]g_list = []for url in url_list:g = gevent.spawn(get_data,url)g_list.append(g)gevent.joinall(g_list)'''
http://www.ifeng.com response
http://www.qq.com response
http://www.baidu.com response
http://www.sina.com.cn response
http://www.taobao.com response
''''''
进程是程序的一次性执行的过程,正在进行的一个过程或者任务,而负责执行任务的是cpu。
进程的生命周期:
当操作系统要完成某个任务的时候它会创建一个进程,当进程完成任务之后,系统就会撤销这个进程,收回它所占用的资源,从创建到撤销的时间段就是进程的生命周期。进程之间存在并发:
在一个操作系统中,同时会存在多个进程,它们就轮流占用cpu资源。并行与并发的区别:
无论并行还是并发,在用户看来其实都是同时运行的,不管是进程还是线程,都只是一个任务而已,真正干活的是cpu,而一个cpu(单核)同一时刻只能执行一个任务。并行:多个任务同时运行,只有具备多个cpu才能真正的实现并行,含有几个cpu,也就意味着同一时间可以执行几个任务。
并发:是伪并行,看起来是同时运行的,实际上是单个cpu在多道程序之间的来回切换。同步与异步的概念:
同步就是指一个进程在执某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到返回信息才能继续执行下去。异步:是指进程不需要一直等待下去,而是继续执行下面的操作,不管其他进程的状态,当有消息返回的时候,系统会通知进程来进行处理,这样可以提高执行效率。比如:打电话的过程就是同步通讯,发短信就是异步通讯
多线程和多进程的关系:
对于计算机密集型应用,应该使用多进程(提高cpu的利用率)
对于IO密集型应用,应该使用多线程,线程的创建比进程的创建开销小的多。
'''
'''
1、进程的创建及与线程的对比
'''
import multiprocessing
import time
import threadingdef func(msg):# 获取当前正在执行进程名字print(multiprocessing.current_process().name)def func2(msg):# 获取当前正在执行进程名字print(threading.current_thread().name)if __name__ == '__main__':t1 = time.time()plist = []for x in range(100):p = multiprocessing.Process(target=func,args=("hello",))p.start()plist.append(p)for p in plist:p.join()t2 = time.time()print(t2-t1) # 7.120407342910767'''分别创建100个进程与100线程,测试他们的耗时时间。'''tlist = []for i in range(100):t = threading.Thread(target=func2,args=("nice",))t.start()tlist.append(t)for t in tlist:t.join()t3 = time.time()print(t3-t2) # 0.027001380920410156'''
2、子进程中要修改全局变量对父进程中的全局变量没有影响
'''
import multiprocessing
from time import sleepnum = [100]def run():global num # num = 100print("子进程开始")num[0] += 1print(num)print("子进程结束")if __name__ == "__main__":print("父进程开始")p = multiprocessing.Process(target=run)p.start()p.join()# 在子进程中要修改全局变量对父进程中的全局变量没有影响# 在创建子进程时对全局变量做了一个备份,父进程中的与子进程中的num是完全不同的两个变量print("父进程结束--%d"%num[0])'''父进程开始子进程开始[101]子进程结束父进程结束--100''''''
3、使用面向对象创建进程
'''
from multiprocessing import Process
import os, timeclass MyProcess(Process): # 继承Processdef __init__(self,name):Process.__init__(self)self.name = namedef run(self):print("子进程(%s-%s)启动" % (self.name, os.getpid()))#子进程的功能time.sleep(3)print("子进程(%s-%s)结束" % (self.name, os.getpid()))if __name__ == "__main__":print("父进程启动")#创建子进程p = MyProcess("test")# 自动调用p进程对象的run方法p.start()p.join()print("父进程结束")'''父进程启动子进程(test-18692)启动子进程(test-18692)结束父进程结束''''''
4-1、进程间的通信1
Queue
'''
from multiprocessing import Process, Queue
import os, timedef write(q):print("启动写子进程%s" % (os.getpid()))for chr in ["A", "B", "C", "D","\n"]:q.put(chr)time.sleep(1)print("结束写子进程%s" % (os.getpid()))def read(q):print("启动读子进程%s" % (os.getpid()))value = Nonewhile value != "\n":value = q.get(True)print("value = " + value)print("结束读子进程%s" % (os.getpid()))if __name__ == "__main__":#父进程创建队列,并传递给子进程q = Queue()pw = Process(target=write, args=(q,))pr = Process(target=read, args=(q,))pw.start()pr.start()pw.join()pr.join()print("父进程结束")'''启动写子进程36000启动读子进程36788value = Avalue = Bvalue = Cvalue = Dvalue = 结束读子进程36788结束写子进程36000父进程结束'''
'''
4-2:进程间的通信2
Manager: Manager可以创建列表、字典、锁、变量、信号、队列等
manager是自带进程锁,在进行修改的时候不必担心多进程同时进行修改的问题。线程才是真正意义上的共享一个内存区域,但线程不自带锁必须自己加锁。manager比较灵活可以实现不同主机间的进程共享
'''
import multiprocessing
import os,time
def func1(tlist):print("子进程开始:", os.getpid())print(len(tlist))tlist[-1] = 10000time.sleep(1)print(tlist)print("子进程结束:", os.getpid())def func2(tlist):print("子进程开始:", os.getpid())print(len(tlist))tlist.reverse()time.sleep(1)print(tlist)print("子进程结束:", os.getpid())if __name__ == '__main__':manager = multiprocessing.Manager()list1 = manager.list(range(10))p1 = multiprocessing.Process(target=func1, args=(list1,))p2 = multiprocessing.Process(target=func2, args=(list1,))p1.start()p2.start()p1.join()p2.join()'''子进程开始: 3756810子进程开始: 3755610[10000, 8, 7, 6, 5, 4, 3, 2, 1, 0]子进程结束: 37568[10000, 8, 7, 6, 5, 4, 3, 2, 1, 0]子进程结束: 37556''''''
5、进程锁:为了解决多个进程同时访问同一资源(读写文件、数据库)产生的冲突,这时候我们使用进程锁来进行解决,在使用进程锁的时候,需要将进程锁作为参数传递到该进程。
'''
def func(lock):with lock:print("加锁",multiprocessing.current_process().name)time.sleep(2)print("释放锁", multiprocessing.current_process().name)if __name__ == '__main__':lock = multiprocessing.Lock()plist = []for i in range(5):p = multiprocessing.Process(target=func,args=(lock,)) # 需要将所传入到子进程中,因为如果父进程结束了,锁就释放了p.start()plist.append(p)# for p in plist: # 父进程结束不影响子进程运行# p.join()print("over")'''over加锁 Process-2释放锁 Process-2加锁 Process-1释放锁 Process-1加锁 Process-4释放锁 Process-4加锁 Process-3释放锁 Process-3加锁 Process-5释放锁 Process-5''' '''
6、信号量:限制同一时间执行的进程的个数。
'''
def func(sem):with sem:print("开始",multiprocessing.current_process().name)time.sleep(1)print("结束", multiprocessing.current_process().name)if __name__ == '__main__':sem = multiprocessing.Semaphore(5)for x in range(10):p = multiprocessing.Process(target=func,args=(sem,))p.start() '''开始 Process-1开始 Process-2开始 Process-3over开始 Process-4开始 Process-5结束 Process-1开始 Process-7结束 Process-2开始 Process-8结束 Process-3开始 Process-6结束 Process-4开始 Process-9结束 Process-5开始 Process-10结束 Process-7结束 Process-8结束 Process-6结束 Process-9结束 Process-10'''
8.Python基础学习笔记day8-正则表达式、网络编程、进程与线程相关推荐
- Python基础学习笔记之(二)
Python基础学习笔记之(二) zouxy09@qq.com http://blog.csdn.net/zouxy09 六.包与模块 1.模块module Python中每一个.py脚本定义一个模块 ...
- Python基础学习笔记之(一)
Python基础学习笔记之(一) zouxy09@qq.com http://blog.csdn.net/zouxy09 前段时间参加微软的windows Azure云计算的一个小培训,其中Pytho ...
- Python基础学习笔记三
Python基础学习笔记三 print和import print可以用,分割变量来输出 import copy import copy as co from copy import deepcopy ...
- Python基础学习笔记(一)
Python基础学习笔记(一) 基本数据类型 整型(int):1.2.10-- 浮点型(float):1.2.2.4.10.00-- 布尔型(bool):True.False 字符串( ...
- Python 基础学习笔记 03
Python基础系列 Python 基础学习笔记 01 Python 基础学习笔记 02 Python 基础学习笔记 03 Python 基础学习笔记 04 Python 基础学习笔记 05 文章目录 ...
- Java基础复习笔记系列 九 网络编程
Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...
- python基础学习笔记——完结
文章目录 一. python概述 1.1 概述 1.2 优缺点 1.3 应用场景 二. python解释器和集成环境的安装 2.1. 编程语言分类 2.2 基本环境搭建 2.3 集成开发环境pycha ...
- Python基础学习笔记(一)python发展史与优缺点,岗位与薪资
相信有好多朋友们都是第一次了解python吧,可能大家也听过或接触过这个编程语言.那么到底什么是python呢?它在什么机缘巧合下诞生的呢?又为什么在短短十几年时间内就流行开来呢?就请大家带着疑问,让 ...
- python爬虫学习笔记一:网络爬虫入门
参考书目 <python网络爬虫从入门到实践>唐松 第一章 网络爬虫入门 1.1 robots协议 举例:查看京东的robots协议 京东robots协议地址 User-agent: * ...
最新文章
- 北航、旷视联合,打造最强实时语义分割网络
- 诺康得NKD完成500万天使轮融资,专注于糖化学细胞治疗...
- 《LeetCode力扣练习》第6题 C语言版 (做出来就行,别问我效率。。。。)
- Flex TextInput只允许输入数字等字符及字符数限制
- java springMVC SSM 操作日志 4级别联动 文件管理 头像编辑 shiro redis
- java中必检异常有哪些_Java面试题经典面试题220道(附答案)
- 【学习笔记】第三章——内存 I(交换技术、进程七状态模型、动态分区分配、动态分区算法)
- 【[USACO09DEC]牛收费路径Cow Toll Paths】
- 面向对象编程引入“人狗大战”小游戏
- java list转json
- JavaSE基础——构造方法 对象的创建步骤 static关键字
- ong拼音汉字_汉语拼音ong的发音方法
- angular中自定义webpack配置
- Day2-Python基础2---列表、元组操作
- python程序设计基础教程ppt_Python程序设计基础教程
- 华北电力大学计算机学硕和专硕,华北电力大学非全日制研究生还分为学硕与专硕?...
- Redis 取消保护模式
- 貌似在ubuntu下架了个web服务器,上传上次的flex调色板
- vs2019社区版下载教程(详细)
- TTS离线语音合成应用方案【一】
热门文章
- 张江男 干物男 宅男
- 当技术重塑健身产业,AI有可能胜过人类教练吗?
- libpcap linux安装,CentOS安装libpcap
- 金士顿16GB Class4 TF卡 和16GB Class10 TF卡有什么区别
- 2019年度中国锂离子电池出口百强榜发布
- 设置允许从网络访问计算机的用户账户(加入guest组),没法访问 您可能没有权限使用网络资源...
- Android 4编程入门经典—开发智能手机与平板电脑应用
- conductor 概念
- 微服务编排 conductor_智能家居巨头 Aqara 基于 KubeSphere 打造物联网微服务平台
- 了不起的互联网老男孩,在创业路上不掉队