线程&线程池
线程
进程和线程:
进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
注意:两个都是过程
线程一个特点:
一个进程中,多个线程共享资源
线程和进程区别:
1. 线程的创建开销小于进程, 创建速度快
2. 同一进程下的多个线程共享该进程的地址空间(资源)
主线程影响其他线程:
是因为线程的概念:
一个进程内默认就会有一个控制线程,该控制线程可以执行代码从而创建新的线程,
该控制线程的执行周期就代表该进程的执行周期
1.一个进程内不开子进程,也不开'子线程' : 主线程结束,该进程就结束
2.当一个进程内开启子进程时 : 主线程结束,主进程要等,等所有子进程运行完毕,给儿子收尸.
3.当一个进程内开启多个线程时 :
主线程结束并不意味着进程结束,
进程的结束指的是该进程内所有的线程都运行完毕,才应该回收进程.
简单点说,就是:
主进程等子进程, 是主进程活都干完了
主线程等子线程,是主进程还没有干完活
(所有的线程都干完活了,该进程才算干完活了)
子进程和线程的id号 验证内存空间
import os
from multiprocessing import Process n = 100
def func():
global n
n = 1
print('子',n,os.getpid()) if __name__ == '__main__':
p = Process(target=func,)
p.start()
print('主',n,os.getpid())
# 主 100 8852 主进程和子进程的id号不一样,说明进程间的内存空间是隔离的
# 子 1 4716 子进程修改变量,主进程感觉不到,说明进程间的内存空间是隔离的
全局变量的修改,验证内存空间
import os
from threading import Thread n = 100 def func():
global n
n = 1
print(current_thread().getName(), n, os.getpid()) if __name__ == '__main__':
t = Thread(target=func,name = ‘func’) #给子线程起名字,不写,默认 Thread-1.Thread-2.....
t.start()
print(current_thread().getName(), n, os.getpid()) # func 1 1088 子线程和主线程的id号一样,说明主线程和子线程在一个进程空间里
# MainThread 1 1088 子线程修改变量n = 1,主线程能感知到,说明线程间共享数据
进程可以看进程号
线程只能看名字了
getName() 测试的时候用的较多
enumerate() 以列表的形式列出当前所有活着的线程
active_count() 统计当前所有活着的线程的个数
import time
from threading import Thread, active_count, enumerate 需要导入threading模块中这两个方法 def func():
time.sleep(3) if __name__ == '__main__':
t = Thread(target=func)
t.start()
print(enumerate())
print(active_count()) # [<_MainThread(MainThread, started 9212)>, <Thread(Thread-1, started 1612)>] 列表形式
# 2 ------------------------------------- print(enumerate()[0].getName()) #enumerate()是一个列表,取索引值[0],再通过getName(),一样能拿到线程的名字
print(current_thread().getName())
#MainThread
#MainThread
os.cpu_count() 查看cpu核数
import os
print(os.cpu_count())
线程池
t = ThreadPoolExecutor() 创建线程池的时候,如果不设置数量,默认是cpu核数*5
证明线程池不设置参数,默认值 是cpu核数*5
import time
import os
from threading import ac-tive_count
from concurrent.futures import ThreadPoolExecutor def func():
time.sleep(1) if __name__ == '__main__':
t = ThreadPoolExecutor() #创建线程池的时候,如果不设置数量,默认是cpu核数*5
for i in range(100):
t.submit(func,)
print(os.cpu_count()) #cpu核数
print(active_count()) #子线程数 + 主线程 #
#21
进程池不要超过cpu核数的2倍(不是真理,具体会根据程序问题的增多,数目相应调大,也和电脑的性能有关)
这个参数肯定不能再程序里面写死,要写到配置文件里,要让软件的使用者( 给运维人员,不是直接给客户)根据他自己的业务场景以及他硬件的性能,要做相应的调整,取配置,所有的支
持并发的软件都是这样做,都应该这样做.不应该在程序里面写死.
多线程+异步调用+requests
requests 库
HTTP客户端库(编写爬虫和测试服务器响应数据时经常用到)
安装:pip install requests
get 请求:
r = requets.get('http://www.baidu.com')
r.text 返回headers中的编码解析的结果
异步调用:
(回调机制:任务执行完,触发回调函数,同时把任务结果传给回调函数)
提交完任务,(为该任务绑定一个回调函数),不用在原地等任务执行完毕拿到结果,可以直接提交下一个任务.
一个任务一旦执行完毕就会自动触发回调函数的运行
不在原地等结果,那么结果哪里去了?
就是通过回调机制
回调函数:add_done_callback(func)
回调函数的参数是单一的:
回调函数的参数就是它所绑定任务的返回值(绑定任务的return)
异步调用,不用等结果 结果去哪了 就是 回调
import requests
import time
from threading import current_thread
from concurrent.futures import ThreadPoolExecutor url = ['https://www.baidu.com',
'https://www.jd.com',
'https://www.python.org',
'http://www.qq.com'] def get(url):
print('get',current_thread().getName(),url) #current_thread().getName()打印哪些线程执行下载任务
time.sleep(2)
r = requests.get(url)
if r.status_code == 200: # 200代表成功下载
return {'url': url, 'text': r.text} def parse(obj):
res = obj.result()
print('parse',current_thread().getName(),res['url'],len(res['text'])) #打印哪些线程执行解析任务 if __name__ == '__main__':
t = ThreadPoolExecutor(2)
for i in url:
t.submit(get,i).add_done_callback(parse) #回调函数
t.shutdown(wait=True)
print(current_thread().getName()) # get ThreadPoolExecutor-0_0 https://www.baidu.com
# get ThreadPoolExecutor-0_1 https://www.jd.com
# parse ThreadPoolExecutor-0_0 https://www.baidu.com 2443
# get ThreadPoolExecutor-0_0 https://www.python.org
# parse ThreadPoolExecutor-0_1 https://www.jd.com 124541
# get ThreadPoolExecutor-0_1 http://www.qq.com
# parse ThreadPoolExecutor-0_1 http://www.qq.com 235464
# parse ThreadPoolExecutor-0_0 https://www.python.org 48856
# MainThread
一直是由线程控制处理
通过进程演示异步概念(不用开新的进程,主进程处理结果)
import requests
import time
import os
from threading import Thread, current_thread
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor url = ['https://www.baidu.com',
'https://www.jd.com',
'https://www.python.org',
'http://www.qq.com'] def get(url):
print('get',os.getpid(),url) #os.getpid()打印哪些进程执行下载任务
time.sleep(3)
r = requests.get(url)
if r.status_code == 200:
return {'url': url, 'text': r.text} def parse(obj):
res = obj.result()
print('parse',os.getpid(),res['url'],len(res['text'])) #os.getpid()打印哪些进程执行解析任务 if __name__ == '__main__':
t = ProcessPoolExecutor(2)
for i in url:
t.submit(get,i).add_done_callback(parse)
t.shutdown(wait=True)
print('\n',os.getpid()) # get 6972 https://www.baidu.com
# get 7180 https://www.jd.com
# get 6972 https://www.python.org
# parse 7856 https://www.baidu.com 2443
# get 7180 http://www.qq.com
# parse 7856 https://www.jd.com 124541
# parse 7856 http://www.qq.com 235464
# parse 7856 https://www.python.org 48856
#
#
线程&线程池的更多相关文章
- GIL 线程/进程池 同步异步
GIL 什么是GIL 全局解释器锁,本质是一把互斥锁,是加在cpython解释器上的一把锁, 同一个进程内的所有线程需要先抢到GIL锁,才能执行python代码 为什么要有GIL cpython解释器 ...
- 常量,字段,构造方法 调试 ms 源代码 一个C#二维码图片识别的Demo 近期ASP.NET问题汇总及对应的解决办法 c# chart控件柱状图,改变柱子宽度 使用C#创建Windows服务 C#服务端判断客户端socket是否已断开的方法 线程 线程池 Task .NET 单元测试的利剑——模拟框架Moq
常量,字段,构造方法 常量 1.什么是常量 常量是值从不变化的符号,在编译之前值就必须确定.编译后,常量值会保存到程序集元数据中.所以,常量必须是编译器识别的基元类型的常量,如:Boolean ...
- 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发
子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...
- C#线程 线程进阶
第四部分:高级线程 非阻塞同步 前面我们说过,即使在分配或增加字段的简单情况下,也需要同步.尽管锁定始终可以满足此需求,但是竞争性锁定意味着线程必须阻塞,从而遭受上下文切换的开销和调度的延迟,这在高度 ...
- Linux线程的实现 & LinuxThread vs. NPTL & 用户级内核级线程 & 线程与信号处理
另,线程的资源占用可见:http://www.cnblogs.com/charlesblc/p/6242111.html 进程 & 线程的很多知识可以看这里:http://www.cnblog ...
- Linux线程 之 线程 线程组 进程 轻量级进程(LWP)
Thread Local Storage,线程本地存储,大神Ulrich Drepper有篇PDF文档是讲TLS的,我曾经努力过三次尝试搞清楚TLS的原理,均没有彻底搞清楚.这一次是第三次,我沉浸gl ...
- JAVA之旅(十五)——多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止
JAVA之旅(十五)--多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止 我们接着多线程讲 一.生产者和消费者 什么是生产者和消费者?我们 ...
- python 进程和线程-线程和线程变量ThreadLocal
线程 线程是由若干个进程组成的,所以一个进程至少包含一个线程:并且线程是操作系统直接支持的执行单元.多任务可以由多进程完成,也可由一个进程的多个线程来完成 Python的线程是真正的Posix Thr ...
- 进程?线程?多线程?同步?异步?守护线程?非守护线程(用户线程)?线程的几种状态?多线程中的方法join()?
1.进程?线程?多线程? 进程就是正在运行的程序,他是线程的集合. 线程是正在独立运行的一条执行路径. 多线程是为了提高程序的执行效率.2.同步?异步? 同步: 单线程 异步: 多线程 3.守护线程? ...
- 关于Spring事务的原理,以及在事务内开启线程,连接池耗尽问题.
主要以结果为导向解释Spring 事务原理,连接池的消耗,以及事务内开启事务线程要注意的问题. Spring 事务原理这里不多说,网上一搜一大堆,也就是基于AOP配合ThreadLocal实现. 这里 ...
随机推荐
- 【学习笔记】深入理解js闭包
本文转载: 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接 ...
- 初学者可能不知道的vue技巧
前言 大家好,这里是@IT·平头哥联盟,我是首席甩锅官——老金,今天给大家分享的,一些日常中神秘而又简单的vue的实用小技巧,以及我在我司项目中实用vue的总结和坑,跟大家一起分享,希望能给其他攻城狮 ...
- 工作笔记:复制文件--从windows到ubuntu,再到fedora
最近在测试跨平台类库,于是写了一些小程序. 当然主要利用vs进行主要的代码开发.eclipse进行linux的调试. 那么需要不时同步项目文件. 考虑到项目简单,所以没有使用svn. 1. 从wind ...
- oracle补丁类型
名称 说明 Release ¤ 标准产品发布.如Oracle Database 10g Release 2的第一个发行版本为10.2.0.1,可以在OTN.edelivery等站点上公开下载 Patc ...
- Bug的分类和管理流程
1.按照严重程度划分 定义:是指Bug对软件质量的破坏程度,即BUG的存在将对软件的功能和性能产生怎样的影响 分类:系统崩溃.严重.一般.次要.建议 2.按优先级划分 定义:表示处理和修正软件缺陷的现 ...
- IIR数字滤波器
对于N阶IIR的计算方程式为: 一阶 Y(n)=a∗X(n)+(1−a)∗Y(n−1) 二阶 y[n]=b0⋅x[n]+b1⋅x[n−1]+b2⋅x[n−2]−a1⋅y[n−1]−a2⋅y[n−2]
- golang 解析json 动态数组
#cat file { "Bangalore_City": "35_Temperature", "NewYork_City": " ...
- VR技术在数据中心3D机房中的应用 (下)
VR技术在数据中心3D机房中的应用 (下) 前面给大家简单科普了一下VR的硬件设备以及VR在各个领域的应用,是不是觉得非常高大上?千言万语概括成一句话,VR能给用户带来前所未有的沉浸感和交互方式,让人 ...
- github 新建一个仓库后
每次都记不住命令,记一下,防止找不到 echo "# learn18" >> README.md git init git add README.md git comm ...
- HDU - 5438 Ponds(拓扑排序删点+并查集判断连通分量)
题目: 给出一个无向图,将图中度数小于等于1的点删掉,并删掉与他相连的点,直到不能在删为止,然后判断图中的各个连通分量,如果这个连通分量里边的点的个数是奇数,就把这些点的权值求和. 思路: 先用拓扑排 ...