线程/进程

一.线程

定义:python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用
threading模块:线程是CPU内核执行的最小单位,通过threading模块可以创建线程。一般不用。
demo01 单线程执行


import threading

def music():

"""听音乐"""

print("music")



def main():

"""创建线程"""

#创建线程并开启

threading.Thread(target=music).start()



if __name__ == '__main__':

main()

demo01 多线程执行

import threading

import time



def music():

"""听音乐"""

while True:

print("music")

time.sleep(1)

def dance():

"""跳舞"""

while True:

print("跳舞")

time.sleep(1)

def main():

"""创建线程"""

#创建线程并开启

threading.Thread(target=music).start()

threading.Thread(target=dance()).start()



if __name__ == '__main__':

main()

二.进程

定义:一个程序运行起来后,代码+用到的资源称之为进程,它是操作系统分配资源的基本单元。
进程的创建:multiprocessing 模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为一个独立的进程,可以执行另外的事情

demo01 进程多任务

#线程是CPU执行的最小单位 ,进程是用来分配CPU资源

#进程的创建

import multiprocessing

import time

import threading



def dance():

while True:

print("跳舞")

time.sleep(1)



def song():

while True:

print("唱歌")

time.sleep(1)



def main():

"""主函数,用于创建多进程"""

print("主进程",multiprocessing.current_process().name)#打印进程信息

print("主线程",threading.current_thread().name) #打印线程信息

multiprocessing.Process(target=dance).start()

multiprocessing.Process(target=song).start()



if __name__ == '__main__':

main()

demo02 使用进程池

# 一个读一个写

import multiprocessing



# 定义一个队列

import time



# 工作中不建议使用进程池,进程池还有bug

# 后期如果开多线程,跟协程还有bug



# 进程的队列

# queue = multiprocessing.Queue(3)



# 进程池的队列,这个吉多专门给进程池创建api,功能上使用上都跟线程的队列是一样

queue = multiprocessing.Manager().Queue(3)



def read():

while True:

print("读")

print(queue.get())

time.sleep(1)

# pool.terminate() # 结束



def write():

while True:

queue.put("123")

print("写")

time.sleep(1)



def main():

# 创建一个进程池

pool = multiprocessing.Pool(2)

# pool.apply(write) # 这种方法是同步方法,进程池中的进程只有一个一个执行

# # pool.terminate()



pool.apply_async(write) # 这个就是不同步

pool.apply_async(read) # 这个直接运行会有bug



# time.sleep(2)

# # 直接关

# pool.terminate() # 关闭

#

# # 如果使用了apply_async这个方法必须使用join

pool.close() # 这个让我们的进程池不在添加其他的进程了

pool.join() # 让我们的主进程等我们一下



if __name__ == '__main__':

main()

demo03 进程的使用

import multiprocessing

import os



import time



num = 0



# 如何确定一个数据是唯一的,进程号+进程内的地址编号这两个确定唯一的数据



def read():

for temp in range(10):

input() # 进程内不能使用input(),这个只能用在主进程内



print("read", num)

print(id(num))

time.sleep(1)

print("子进程", os.getpid())

print("子进程", os.getppid()) # 那个进程创建了你



def main():

# input()



print("主进程:", id(num), os.getpid())



"""进程"""

multiprocessing.Process(target=read).start()



if __name__ == '__main__':

main()

三.协程

定义:协程又称微线程 ,是python中另外一种实现多任务的方式,占用比线程更小的执行单位。
迭代器:for … in … 是常见的迭代器模型。迭代器是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象/只能往前不能退后。我们可以通过next()方法,获取下一数据。这里L就是迭代器 L = [ x2 for x in range(5)]
生成器:为了达到记录当前状态,并撇和next() 函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)生成器是一类特殊的迭代器。 这里G就是生成器 G = ( x
2 for x in range(5))
2.简单实现协程yield

demo01 简单实现协程

import time



def work1():

while True:

print("--------work1----------")

yield

time.sleep(0.5)



def work2():

while True:

print("--------work2----------")

yield

time.sleep(0.5)



if __name__ == '__main__':



w1 = work1()

w2 = work2()



while True:

next(w1)

next(w2)

3.协程 - greenlet

greenlet模块对协程进行了封装,从而使得切换任务变得简单
使用greenlet,必须使用 .switch() 进行任务切换

安装greenlet模块: $ sudo pip3 install greenlet
demo02

#greenlet 协程

from greenlet import greenlet

import time



def dance():

"""dance"""

while True:

print("------dance--------")

time.sleep(0.5)

gr2.switch()



def music():

"""music"""

while True:

print("------music--------")

time.sleep(0.5)

gr1.switch()



gr1 = greenlet(dance)

gr2 = greenlet(music)



def main():

"""greenlet协程"""

gr1.switch()



if __name__ == '__main__':

main()

4.协程 - gevent

gevent模块:由于IO操作非常耗时,经常使程序处于等待状态,gevent 为我们自动切换协程,保证了总有greenlet在执行,而不是等待IO.
gevent模块安装:pip3 install gevent
demo01 gevent协程的使用

import gevent #协成的库 ,只有在python中才有多任务

import time



def dance():

"""跳舞"""

while True:

print("跳舞")

gevent.sleep(1)



def song():

"""唱歌"""

while True:

print("唱歌")

gevent.sleep(1)



def main():

"""主函数"""

spawn_dance = gevent.spawn(dance)

spawn_song = gevent.spawn(song)



#加入join

spawn_dance.join()

spawn_song.join()



if __name__ == '__main__':

main()

demo02 协程的耗时使用补丁

import gevent

import time



#请求Monkey来打补丁

from gevent import monkey

#把所有耗时的api在执行的时候自动换成gevent中的耗时api

#使用协成必须使用monkey打补丁

monkey.patch_all()



def dance():

"""跳舞"""

while True:

print("跳舞")

gevent.sleep(1)



# from greenlet import greenlet



def song():

"""唱歌"""

while True:

print("唱歌")

gevent.sleep(1)



def main():

"""主函数,协成版唱歌跳舞"""

#把任务放到协成中

spawn_dance = gevent.spawn(dance)

spawn_song = gevent.spawn(song)



#加入join

spawn_dance.join()

spawn_song.join()



if __name__ == '__main__':

main()

5.案例:并发下载器

demo01 并发下载原理

from gevent import monkey

import gevent import urllib.request # 有耗时操作时需要

monkey.patch_all()

def my_downLoad(url):

print('GET: %s' % url)

resp = urllib.request.urlopen(url)

data = resp.read()

print('%d bytes received from %s.' % (len(data), url))

gevent.joinall([

gevent.spawn(my_downLoad, 'http://www.baidu.com/'),

gevent.spawn(my_downLoad, 'http://www.itcast.cn/'),

gevent.spawn(my_downLoad, 'http://www.itheima.com/'),

])

四. http协议的请求和相应

请求: 构成(请求头,空行 ,请求体)
请求头 :请求方式 请求地址 http协议 (GET/index.html HTTP/1.1)

换行符 :\r\n

GET请求的格式 :

GET /path HTTP/1.1

Header1: Value1

Header2: Value2

...

每个Header一行一个 ,换行符 是 \r\n



POST请求的格式:

POST /path HTTP/1.1

Header1: Value1

Header2: Value2



body date goes here...

当遇到连续两个\r\n时 ,Header部分结束,后面的数据全部是body



响应 : 构成(响应头 空行 响应体)
HTTP/1.1 200 OK\r\n

\r\n

body
上一篇:多任务—协程


下一篇:《Python》线程池、携程