day33 python学习 多线程
线程的概念
进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
三 线程与进程的区别
1
1.线程的创建开销小(无需申请内存空间或者资源),创建线程的速度快,(但是不能无限开)
2.同一个进程下的多个线程,共享该进程地址空间的资源(数据等内容)
3.改变线程,会影响其他线程(在同一个进程的内存空间内的线程) 但是改变主进程,不会影响子进程
- Threads share the address space of the process that created it; processes have their own address space.
- 进程分享创建他的留给他们的地址空间,而进程们却又自己的地址空间
- Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
- 线程直接访问进程的数据段;进程拥有父进程的数据段的自身副本。
- Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
- New threads are easily created; new processes require duplication of the parent process.
- Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
- Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
四 为何要用多线程
多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:
1. 多线程共享一个进程的地址空间
2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)
开启线程的两种方式
与开启进程的方式类似
from threading import Thread
def piao(name,n):
print('%s is piaoing %s and%s'%(name,n,os.getpid())) if __name__ == '__main__':
t=Thread(target=piao,args=('alex',11,)) #这里的写法要注意,
t.start()
print('zhu')
常用方式,
from threading import Thread
import os
class Piao(Thread):
def __init__(self,name):
super(Piao, self).__init__()
self.name=name
def run(self): # 方法名一定要写成RUN 的形式否则不行
print('%s is piaoing'%self.name) if __name__ == '__main__':
t=Piao('alex')
t.start() print('主')
利用类的继承开启线程,不太常用,但是要会
六 守护线程
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁
需要强调的是:运行完毕并非终止运行
#1.对主进程来说,运行完毕指的是主进程代码运行完毕 #2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
详细解释:
#1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束, #2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,
而进程必须保证非守护线程都运行完毕后才能结束。
线程池:与进程池概念类似(引入进程池模块就可以了,无须再引入Thread模块)
池的目的:当有很大的工作量需要去完成的时候,需要限制每次进入线程(或者进程)的数量。
from concurrent.futures import ThreadPoolExecutor #引入线程池模块
def piao(name):
print('%s is piao ing '%name) if __name__ == '__main__':
t=ThreadPoolExecutor(4) #
objs=[]
for i in range(10):
obj=t.submit(piao,'alex')
objs.append(obj)
t.shutdown(wait=True)
for obj in objs:
print(obj.result())
print('zhu')
进程池
- 很明显需要并发执行的任务通常要远大于核数
- 一个操作系统不可能无限开启进程,通常有几个核就开几个进程
- 进程开启过多,效率反而会下降(开启进程是需要占用系统资源的,而且开启多余核数目的进程也无法做到并行)
ps:对于远程过程调用的高级应用程序而言,应该使用进程池,Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,
如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,
直到池中有进程结束,就重用进程池中的进程。
from concurrent.futures import ProcessPoolExecutor
import os,time
n=100
def piao(name):
print('%s is piaoing'%name,os.getpid())
time.sleep(1)
global n
return n**2
if __name__ == '__main__':
p=ProcessPoolExecutor(4)
objs=[]
for i in range(10):
obj=p.submit(piao,i)
objs.append(obj)
p.shutdown(wait=True)
for obj in objs:
print(obj.result())
print('zhu',os.getpid())
打印结果如下:: 可以看到四个进程的进程ID 都是固定的,这就是进程池,当当前进程完成后进入下一个进程,此时还是用的这些进程ID
证明进程池是开
0 is piaoing 1348
1 is piaoing 14076
2 is piaoing 13816
3 is piaoing 13756
4 is piaoing 1348
5 is piaoing 14076
6 is piaoing 13816
7 is piaoing 13756
8 is piaoing 1348
9 is piaoing 14076
t.submit(func1,obj).add_done_callback(函数名) 回调函数
from concurrent.futures import ThreadPoolExecutor
import time
from threading import current_thread
import requests #模拟浏览器,走HTTP协议发送请求,模块下载网页
def func1(url):
print('%s GET %s'%(current_thread().getName(),url)) #得到当前线程的名称
response=requests.get(url) #得到网页内容
time.sleep(3)
if response.status_code==200: #status_code response的返回的状态码,当为200时才表示下载成功
return{'url':url,'text':response.text}#response.text 得到下载的内容
def res(obj):
ret=obj.result()
print('[%s]<%s> %s'%(current_thread().getName(),ret['url'],len(ret['text']))) if __name__ == '__main__':
t=ThreadPoolExecutor(2)
urllis=[
'https://www.jd.com',
'https://www.tmall.com',
'https://www.baidu.com',
'https://www.douban.com'
]
for url in urllis:
t.submit(func1,url).add_done_callback(res) #回调函数,将函数func1执行的结果返回给res,
#在res中用 .result()的方式来取出返回值
t.shutdown(wait=True)
print('zhu')
import struct
a=struct.pack('i',11111)
print(a)
for i in a:
print(bin(i))
print(bin(11111))
day33 python学习 多线程的更多相关文章
- Python学习——多线程,异步IO,生成器,协程
Python的语法是简洁的,也是难理解的. 比如yield关键字: def fun(): for i in range(5): print('test') x = yield i print('goo ...
- python学习-多线程并发
1.线程与进程 通俗解释: 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进 ...
- python学习笔记- 多线程(1)
学习多线程首先先要理解线程和进程的关系. 进程 计算机的程序是储存在磁盘中的可执行的二进制文件,执行时把这些二进制文件加载到内存中,操作系统调用并交给处理器执行对应操作,进程是程序的一次执行过程,这是 ...
- Python学习笔记(三)多线程的使用
这节记录学习多线程的心得. Python提供了thread模块,不过该模块的缺点很多,例如无法方便的等待线程结束,所以我们使用更加高级的threading模块. threading模块的使用一 ...
- python学习笔记-(十三)线程&多线程
为了方便大家理解下面的知识,可以先看一篇文章:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html 线程 1.什么是线程? ...
- python学习笔记(二十九)为什么python的多线程不能利用多核CPU
问题:为什么python的多线程不能利用多核CPU,但是咱们在写代码的时候,多线程的确是在并发,而且还比单线程快原因:因为GIL,python只有一个GIL,运行python时,就要拿到这个锁才能执行 ...
- python学习笔记(二十七)多线程与多进程
线程是程序里面的最小执行单元. 进程是资源的集合. 线程是包含在一个进程里面,一个进程可以有多个线程,一个进程里面默认有一个主线程.由主线程去启动子线程. 1.多线程 import threading ...
- python学习笔记之使用threading模块实现多线程(转)
综述 Python这门解释性语言也有专门的线程模型,Python虚拟机使用GIL(Global Interpreter Lock,全局解释器锁)来互斥线程对共享资源的访问,但暂时无法利用多处理器的优势 ...
- Python学习之路14☞多线程与多进程
一 进程与线程的概念 1.1 进程 进程定义: 进程就是一个程序在一个数据集上的一次动态执行过程.进程一般由程序.数据集.进程控制块三部分组成.我们编写的程序用来描述进程要完成哪些功能以及如何完成:数 ...
随机推荐
- js获取表格视图所选行号的ids
实例化数组 遍历所选行push到数组中 将数组join转换为以,分割的字符串 /*获取指定id的datagrid的表格视图的选择的ids*/ function getDataGridSelectRow ...
- 41 MYSQL 索引和慢查询优化
一 .索引mysql 索引 b+tree 本质:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数 ...
- hdu1686字符串kmp
The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e ...
- mysql日期查询大全
-- 查询昨日一整天的数据 DAY) ,'%Y-%m-%d 23:59:59') AS '昨日结束时间' -- 查询今日开始到当前时间的数据 DAY) ,'%Y-%m-%d %H:%i:%s') AS ...
- 使用CLOB抛出数字或值错误异常
今天在调试某个问题的时候,由于使用了很多循环,我需要都打印出来,试图使用clob整体处理之后再打印. 最后抛出此异常:数字或值错误. 网友解释如下: $ oerr ora 650206502, 000 ...
- spring--boot @Valid的使用
spring--boot @Valid的使用 每天一个小知识点,每天进步一点点,总结是积累. springBoot @Valid的使用,解释一下.就是给摸个bean类属性(数据库字段)加一个门槛,比如 ...
- 【转】json与jsonp区别浅析(json才是目的,jsonp只是手段)
一言以蔽之,json返回的是一串数据:而jsonp返回的是脚本代码(包含一个函数调用): JSON其实就是JavaScript中的一个对象,跟var obj={}在质上完全一样,只是在量上可以无限扩展 ...
- PHP:第一章——php中的输出函数
<?php //PHP中的输出函数 //echo()函数输出一个或多个字符串: echo 'PHP中的echo<br/>'; //var_dump()此函数显示关于一个或多个表达式的 ...
- html <table>标签信息
table的属性 border pixcels 规定表格边框的宽度 cellpadding picels/% 规定单元格边沿与内容之间的空白 cellspacing picels/% 规定表格以及单元 ...
- storage路径问题
1 概念总述 android开发中,关于存储路径,我们经常听到以下几个概念:内存.内部存储和外部存储,现在我们就来详细说说这三者区别与联系. 内存:英文中记为memory,即RAM 内部存储:英文记为 ...