本节内容

一、线程进程介绍

二、 线程

  1、线程基本使用 (Threading)

  2、线程锁(Lock、RLock)

  3、信号量(Semaphore)

  4、事件(event)

  5、条件(Condition)

  6、定时器 (Timer)

  7、线程池 (ThreadPoolExecutor)

三、进程

  1、进程基本使用

  2、进程数据共享

  3、进程池

四、协程

一、线程进程介绍

1. 工作最小单元是线程

2. 应用程序 -> 至少有一个进程 -> 至少有一个线程

3. 应用场景:

  IO密集型:线程

  计算密集型:进程

4. GIL,全局解释器锁

保证同一个进程中只有一个线程同时被调度,如图所示

二、线程

1、线程基本使用

import threading
import time def func(*args):
time.sleep(1)
print(*args) for i in range(10):
t = threading.Thread(target=func, args=[i,])
t.start() # 程序准备好了,等待CPU调度 print('--main thread--')
print('线程总数:',threading.activeCount()) # 主线程先执行完,等待所有其它线程再执行完,最终程序执行完

上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

更多方法:

  • start            线程准备就绪,等待CPU调度

  • setName      为线程设置名称

  • getName      获取线程名称

  • setDaemon   设置为后台线程或前台线程(默认)

    如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止

    如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

  • join              逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

  • run              线程被cpu调度后自动执行线程对象的run方法

 import threading
import time def func(*args):
time.sleep(1)
print(*args) for i in range(30):
t = threading.Thread(target=func, args=[i,]) # t.setDaemon(True) # 主线程终止,不等待子线程
t.start() # 程序准备好了,等待CPU调度 t.join() # 一直等,线程串行了
t.join(1) # 等待最大时间 print('--main thread--')
print('线程总数:',threading.activeCount())

join和setDeamon方法

class MyThread(threading.Thread):

    def __init__(self, func, *args, **kwargs):
super(MyThread,self).__init__(*args, **kwargs)
# self._target = target
self.func = func def run(self): # 线程内部自动执行run方法,定制
self.func() def task():
time.sleep(1)
print("*") obj = MyThread(task)
obj.start()

自定义Threading

2、线程锁(Lock、RLock)

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,

所以,出现了线程锁 - 同一时刻允许一个线程执行操作。

import threading
import time
v = 10 # 只能有一个人使用锁 # lock = threading.Lock()
lock = threading.RLock() # 开多重锁 def task(arg):
time.sleep(2) # 模拟可以并发代码
# 申请使用锁,其他人等
lock.acquire()
lock.acquire()
global v
v -= 1
print(v)
# 释放锁
lock.release()
lock.release() for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start()

  

3、信号量(Semaphore)

互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,

后面的人只能等里面有人出来了才能再进去。

import threading
import time
v = 10 # 多人同时使用锁
lock = threading.BoundedSemaphore(3) def task(arg): # 申请使用锁,其他人等
lock.acquire()
time.sleep(1)
global v
v -= 1
print(v) # 释放锁
lock.release() for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start()

  

4、事件(event)

python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,

那么event.wait 方法时便不再阻塞。

  • clear:将“Flag”设置为False

  • set:将“Flag”设置为True

import threading
import time lock = threading.Event() def task(arg):
time.sleep(1)
# 锁住所有线程
lock.wait()
print(arg) for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start() while True:
value = input(">>>>:")
if len(value) == 0:
continue
if value == 'q':
exit()
if value == '1':
lock.set()
lock.clear()

  

5、条件(Condition)

使得线程等待,只有满足某条件时,才释放n个线程

import threading
import time lock = threading.Condition() def task(arg):
time.sleep(1) # 锁住所有线程
lock.acquire()
lock.wait() print('线程:', arg) lock.release() for i in range(10):
t = threading.Thread(target=task, args=(i,))
t.start() while True:
value = input(">>>:") lock.acquire()
lock.notify(int(value)) # 输入几个就解锁几个线程
lock.release()

  

6、定时器 (Timer)

定时器,指定n秒后执行某操作

from threading import Timer

def hello():
print("hello, world") t = Timer(1, hello)
t.start() # after 1 seconds, "hello, world" will be printed

  

7、线程池

涉及到多线程的使用时,我们更多使用线程池来解决问题

from concurrent.futures import ThreadPoolExecutor
import requests # pip3 install requests def task(url):
response = requests.get(url)
print("得到结果:", url, len(response.content)) pool = ThreadPoolExecutor(2) url_list = [
'http://www.oldboyedu.com',
'http://www.autohome.com.cn',
'http://www.baidu.com',
'http://www.miaocloud.cn'
] for url in url_list:
print("开始请求", url)
pool.submit(task, url)

  

from concurrent.futures import ThreadPoolExecutor
import requests # pip3 install requests def txt(future):
download_response = future.result()
print('处理中', download_response.url, download_response.status_code) def download(url):
response = requests.get(url)
return response pool = ThreadPoolExecutor(2) url_list = [
'http://www.oldboyedu.com',
'http://www.autohome.com.cn',
'http://www.baidu.com',
'http://www.miaocloud.cn'
] for url in url_list:
# 去连接池中获取链接
# 去下载吧
print("开始请求", url)
future = pool.submit(download, url) # 下载完成之后,执行txt函数
future.add_done_callback(txt) # 其中txt的输入参数必须为future

有回调函数的线程池

三、进程

1、进程基本使用

from multiprocessing import Process

def task(arg):
print(arg) if __name__ == "__main__":
for i in range(10):
p = Process(target=task, args=(i,))
# p.daemon = True
p.start()
# p.join()
p.join(1) print('主进程中的主线程执行到最后...')

注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。

2、进程数据共享

进程各自持有一份数据,默认无法共享数据

 def task(num, li):
li.append(num)
print(li) if __name__ == "__main__":
v = [] # 每个进程都拷贝一份
for i in range(10):
p = Process(target=task, args=(i, v))
# p = Thread(target=task, args=(i, v))
p.start()

进程间默认无法共享数据

from multiprocessing import Process, Array, Manager

# 方法一 Array
def task(num, array):
array[num] = 1
print(list(array)) if __name__ == "__main__":
a = Array('i', 10)
for i in range(10):
p = Process(target=task, args=(i, a))
p.start() # 方法二 Manager.dict()
def task(num, list1):
list1.append(num)
print(list1) if __name__ == "__main__": obj = Manager() # 基于socket实现
list1 = obj.list() # 可以实现数据共享
# dict1 = ojb.dict() for i in range(10):
p = Process(target=task, args=(i, list1))
p.start()
# p.join()

  

    'c': ctypes.c_char,  'u': ctypes.c_wchar,
'b': ctypes.c_byte, 'B': ctypes.c_ubyte,
'h': ctypes.c_short, 'H': ctypes.c_ushort,
'i': ctypes.c_int, 'I': ctypes.c_uint,
'l': ctypes.c_long, 'L': ctypes.c_ulong,
'f': ctypes.c_float, 'd': ctypes.c_double

类型对照表

当创建进程时(非使用时),共享数据会被拿到子进程中,当进程中执行完毕后,再赋值给原值。

3、进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,

直到进程池中有可用进程为止。

from concurrent.futures import ProcessPoolExecutor

pool = ProcessPoolExecutor(5)

def task(arg):
pass for i in range(10):
pool.submit(task, i)
四、协程

线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。

协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;

from gevent import monkey;  monkey.patch_all()
import gevent
import requests
# 根据协程二次开发: 协程 + IO def f(url):
response = requests.get(url)
print(response.url,response.status_code) gevent.joinall(
[
gevent.spawn(f, 'http://www.baidu.com'),
gevent.spawn(f, 'http://www.jd.com'),
gevent.spawn(f, 'http://www.taobao.com'),
]
)

  

Python自动化开发 -进程、线程和协程(二)的更多相关文章

  1. python系列7进程线程和协程

    目录 进程 线程 协程  上下文切换 前言:线程和进程的关系图 由下图可知,在每个应用程序执行的过程中,都会去产生一个主进程和主线程来完成工作,当我们需要并发的执行的时候,就会通过主进程去生成一系列的 ...

  2. python进程.线程和协程的总结

    I.进程: II.多线程threading总结 threading用于提供线程相关的操作,线程是应用系统中工作的最小单位(cpu调用的最小单位). Python当前版本的多线程没有实现优先级,线程组, ...

  3. python 自动化之路 day 10 协程、异步IO、队列、缓存

    本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 RabbitMQ队列 Redis\Memcached缓存 Paramiko SSH Twsited网络框架 引子 到目 ...

  4. Python自动化开发 - 进程、线程(一)

    本节内容 1.操作系统发展史 2.进程和线程 3.Python threading 模块 一.操系统发展史 手工操作(无操作系统) 1946年第一台计算机诞生--20世纪50年代中期,还未出现操作系统 ...

  5. python自动化开发学习 进程, 线程, 协程

    python自动化开发学习 进程, 线程, 协程   前言 在过去单核CPU也可以执行多任务,操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换任务2,任务2执行0.01秒,在切换到任务3,这 ...

  6. python自动化开发-[第十天]-线程、协程、socketserver

    今日概要 1.线程 2.协程 3.socketserver 4.基于udp的socket(见第八节) 一.线程 1.threading模块 第一种方法:实例化 import threading imp ...

  7. Python学习之路--进程,线程,协程

    进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者消费者模型 Q ...

  8. 三、进程和线程、协程在python中的使用

    三.进程和线程.协程在python中的使用 1.多进程一般使用multiprocessing库,来利用多核CPU,主要是用在CPU密集型的程序上,当然生产者消费者这种也可以使用.多进程的优势就是一个子 ...

  9. 图解Python 【第八篇】:网络编程-进程、线程和协程

    本节内容一览图: 本章内容: 同步和异步 线程(线程锁.threading.Event.queue 队列.生产者消费者模型.自定义线程池) 进程(数据共享.进程池) 协程 一.同步和异步 你叫我去吃饭 ...

随机推荐

  1. __PRETTY_FUNCTION__, __FUNCTION__, __func__

    __PRETTY_FUNCTION__, __FUNCTION__, __func__这三者的区别是什么? http://stackoverflow.com/questions/4384765/wha ...

  2. cesium 中地图发生了平移,放缩,旋转等动作所要执行的动作

    1.在canvas上得到鼠标点击的是那个键 <html><head><title>js判断鼠标左.中.右键哪个被点击-柯乐义</title><sc ...

  3. gerrit管理下的git代码提交小技巧

    1.提交代码git checkout targetbranch 切换至目标分支git pull origin targetbranch 拉取目标分支最新内容git add 修改文件git commit ...

  4. LoibreOJ 2042. 「CQOI2016」不同的最小割 最小割树 Gomory-Hu tree

    2042. 「CQOI2016」不同的最小割 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  5. WIN7成功安装Qt4.8方法,无需VS支持

    下载地址:http://pan.baidu.com/share/link?shareid=159827&uk=4010603727 安装Qt方法 安装准备:1. qt-win-opensour ...

  6. Delphi,C语言互通脚本引擎研究

    基于大神akuma的脚本引擎. 下面是demo

  7. Max Chunks To Make Sorted II LT768

    This question is the same as "Max Chunks to Make Sorted" except the integers of the given ...

  8. 编译https://github.com/CIR-KIT/steer_drive_ros时出现的问题

    解决gazebo对应的protobuf版本问题: I've come across to the same problem. I'm using Ubuntu 16.04, ROS Kinetic a ...

  9. NOIP水题测试(2017082501)

    日常水题测试又来了! 以后答案都以单题形式公布. 下面看今天的水题: 时间限制:5小时 题目一:无法形容的水 题目二:比上一题还水 题目三:一元三次方程求解 题目四:单词接龙 题目五:统计单词个数 题 ...

  10. Web中的四大作用域对象

    request:请求对象 类型:HttpServletRequest session:表示一次会话,可以处理一个用户多个页面之间的请求 application:标识web应用上下文,类型:Servle ...