python并发之多线程
一开启线程的两种方式
- from threading import Thread
- import time
- def haha(name):
- time.sleep(2)
- print('%s 你大爷......'%name)
- if __name__ == '__main__':
- t=Thread(target=haha,args=('一根',))
- t.start()
- t.join()
- print('主')
- from threading import Thread
- import time
- def jiji(eat):
- time.sleep(1)
- print('%s 富贵,你吃了什么???'%eat)
- if __name__ == '__main__':
- time.sleep(2)
- t=Thread(target=jiji,args=('屎',))
- t.start()
- print('主')
方式一
- from threading import Thread
- import time
- class hh(Thread):
- def __init__(self,name):
- super().__init__()
- self.name=name
- def play(self):
- time.sleep(2)
- print('%s basket-ball......'%self.name)
- if __name__ == '__main__':
- t=hh('王浩')
- t.start()
- print('主线程')
方式二
二在一个进程下开启多个线程与在一个进程下开启多个子进程的区别
- from multiprocessing import Process
- from threading import Thread
- import os
- def work():
- print('hello')
- if __name__ == '__main__':
- #在主线程下来气进程
- t=Thread(target=work)
- t.start()
- print('主线程/主进程')
- '''
- 打印结果:
- hello
- 主线程/主进程
- '''
- #在主进程下开启子进程
- t=Process(target=work)
- t.start()
- print('主线程/主进程')
- '''
- 打印结果:
- 主线程/主进程
- hello
- '''
子线程比子进程打印的快
- from multiprocessing import Process
- from threading import Thread
- import os
- def work():
- print('hello',os.getpid())
- if __name__ == '__main__':
- #part1:在主进程下开启多个线程,每个线程都和主进程的pid一样
- t1=Thread(target=work)
- t2=Thread(target=work)
- t1.start()
- t2.start()
- print('主线程/主进程pid',os.getpid())
- #part2:开启多个进程,每个进程都有着不同的pid
- p1=Process(target=work)
- p2=Process(target=work)
- p1.start()
- p2.start()
- print('主线程/主进程pid',os.getpid())
pid
- from threading import Thread
- from multiprocessing import Process
- import os
- def work():
- global n
- n=0
- if __name__ == '__main__':
- n=100
- p=Process(target=work)
- p.start()
- p.join()
- print('主',n) #毫无疑问子进程p已经将自己的全局的n改成了0,当改的仅仅是他自己的,父进程n任然是100
- n=1
- t=Thread(target=work)
- t.start()
- t.join()
- print('主',n)#查看结果为0,因为同一进程内的线程之间共享进程内的数据
同一进程内的线程共享该进程的数据
三练习
- import multiprocessing
- import threading
- import socket
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- s.bind(('127.0.0.1',8080))
- s.listen(5)
- def action(conn):
- while True:
- data=conn.recv(1024)
- print(data)
- conn.send(data.upper())
- if __name__ == '__main__':
- while True:
- conn,addr=s.accept()
- p=threading.Thread(target=action,args=(conn,))
- p.start()
- 多线程并发的socket服务端
多线程并发的socket服务端
- import socket
- s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- s.connect(('127.0.0.1',8080))
- while True:
- msg=input('>>: ').strip()
- if not msg:continue
- s.send(msg.encode('utf-8'))
- data=s.recv(1024)
- print(data)
客户端
2三个任务,一个接收用户输入,一个将用户输入的内容格式化成大写,一个将格式化后的结果存入文件
- from threading import Thread
- msg_l=[]
- format_l=[]
- def talk():
- while True:
- msg=input('>>: ').strip()
- if not msg:continue
- msg_l.append(msg)
- def format_msg():
- while True:
- if msg_l:
- res=msg_l.pop()
- format_l.append(res.upper())
- def save():
- while True:
- if format_l:
- with open('db.txt','a',encoding='utf-8') as f:
- res=format_l.pop()
- f.write('%s\n' %res)
- if __name__ == '__main__':
- t1=Thread(target=talk)
- t2=Thread(target=format_msg)
- t3=Thread(target=save)
- t1.start()
- t2.start()
- t3.start()
四线性相关其他知识
- Thread实例对象的方法
- isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- setName(): 设置线程名。
- threading模块提供的一些方法:
- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前
终止后的线程。
hreading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
- from threading import Thread
- import threading
- from multiprocessing import Process
- import os
- def work():
- import time
- time.sleep(3)
- print(threading.current_thread().getName())
- if __name__ == '__main__':
- #在主进程下开启线程
- t=Thread(target=work)
- t.start()
- print(threading.current_thread().getName())
- print(threading.current_thread()) #主线程
- print(threading.enumerate()) #连同主线程在内有两个运行的线程
- print(threading.active_count())
- print('主线程/主进程')
- '''
- 打印结果:
- MainThread
- <_MainThread(MainThread, started 140735268892672)>
- [<_MainThread(MainThread, started 140735268892672)>, <Thread(Thread-1, started 123145307557888)>]
- 主线程/主进程
- Thread-1
- '''
主线程等待子线程结束
- from threading import Thread
- import time
- def sayhi(name):
- time.sleep(2)
- print('%s say hello' %name)
- if __name__ == '__main__':
- t=Thread(target=sayhi,args=('egon',))
- t.start()
- t.join()
- print('主线程')
- print(t.is_alive())
- '''
- egon say hello
- 主线程
- False
- '''
五守护线程
无论进程还是线程,都是守护主进程运行结束后自动销毁,那么运行接受又是在那种情况下的呢?
1主进程在其代码结束后就算运行结束了(守护进程就会被销毁),主进程就会等待非守护的子进程运行结束后回收其资源,才会结束。
2主线程在其他非守护进程完毕后才算完(守护进程被销毁),主线程结束意味着进程结束,进程整体资源被回收,所以主线程必须在其他线程结束后才结束
- from threading import Thread
- import time
- def sayhi(name):
- time.sleep(2)
- print('%s say hello' %name)
- if __name__ == '__main__':
- t=Thread(target=sayhi,args=('egon',))
- t.setDaemon(True) #必须在t.start()之前设置
- t.start()
- print('主线程')
- print(t.is_alive())
- '''
- 主线程
- True
- '''
- from threading import Thread
- import time
- def foo():
- print(123)
- time.sleep(1)
- print("end123")
- def bar():
- print(456)
- time.sleep(3)
- print("end456")
- t1=Thread(target=foo)
- t2=Thread(target=bar)
- t1.daemon=True
- t1.start()
- t2.start()
- print("main-------")
- 迷惑人的例子
有点挖坑的意思哦
六 Python GIL(Global Interpreter Lock)
定义:
在CPython中,全局解释器锁是一个互斥锁,它可以防止多个对象的出现。
本地线程同时执行Python的一组语言。这个锁是主要的
因为CPython的内存管理不是线程安全的。(然而,由于吉尔
存在,其他的特性已经发展到依赖于它所执行的保证。)
结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势。
1. 多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能
2. 每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处
结论:
对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用
当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),这是因为一个程序基本上不会是纯计算或者纯I/O,所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型。
- #分析:
- 我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是:
- 方案一:开启四个进程
- 方案二:一个进程下,开启四个线程
- #单核情况下,分析结果:
- 如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜
- 如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜
- #多核情况下,分析结果:
- 如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜
- 如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜
- #结论:现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。
- from multiprocessing import Process
- from threading import Thread
- import os,time
- def work():
- res=0
- for i in range(100000000):
- res*=i
- if __name__ == '__main__':
- l=[]
- print(os.cpu_count()) #本机为4核
- start=time.time()
- for i in range(4):
- p=Process(target=work) #耗时5s多
- p=Thread(target=work) #耗时18s多
- l.append(p)
- p.start()
- for p in l:
- p.join()
- stop=time.time()
- print('run time is %s' %(stop-start))
计算密集型:多进程效率高
- from multiprocessing import Process
- from threading import Thread
- import threading
- import os,time
- def work():
- time.sleep(2)
- print('===>')
- if __name__ == '__main__':
- l=[]
- print(os.cpu_count()) #本机为4核
- start=time.time()
- for i in range(400):
- # p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
- p=Thread(target=work) #耗时2s多
- l.append(p)
- p.start()
- for p in l:
- p.join()
- stop=time.time()
- print('run time is %s' %(stop-start))
I/O密集型:多线程效率高
应用:
多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析
python并发之多线程的更多相关文章
- python高级之多线程
python高级之多线程 本节内容 线程与进程定义及区别 python全局解释器锁 线程的定义及使用 互斥锁 线程死锁和递归锁 条件变量同步(Condition) 同步条件(Event) 信号量 队列 ...
- python 类变量 在多线程下的共享与释放问题
最近被多线程给坑了下,没意识到类变量在多线程下是共享的,还有一个就是没意识到 内存释放问题,导致越累越大 1.python 类变量 在多线程情况 下的 是共享的 2.python 类变量 在多线程情况 ...
- python中的多线程【转】
转载自: http://c4fun.cn/blog/2014/05/06/python-threading/ python中关于多线程的操作可以使用thread和threading模块来实现,其中th ...
- Python之FTP多线程下载文件之分块多线程文件合并
Python之FTP多线程下载文件之分块多线程文件合并 欢迎大家阅读Python之FTP多线程下载系列之二:Python之FTP多线程下载文件之分块多线程文件合并,本系列的第一篇:Python之FTP ...
- Python之FTP多线程下载文件之多线程分块下载文件
Python之FTP多线程下载文件之多线程分块下载文件 Python中的ftplib模块用于对FTP的相关操作,常见的如下载,上传等.使用python从FTP下载较大的文件时,往往比较耗时,如何提高从 ...
- Python系列之多线程、多进程
线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线程的支持,Python也不例外,并且,Python的线程是真正的Posix Thread,而不是模拟出来的线程. Python的标准库提供 ...
- Python 简单理解多线程
进程,是一个或多个线程的集合,每个进程在内存中是相对独立的. 线程,是计算机最小的运算单元,每个进程至少要有一个线程,多个线程时,每个线程间之间共享内存. 分别举例常规运行和多线程运行: 0)常规运行 ...
- python中的多线程
一个程序可以理解为一个进程,这个进程有其代号,可以依据这个代号将其杀死. 一个进程肯定有且只有一个主线程,他可以有很多子线程. 运行一个任务如果可以有许多子线程同时去做,当然会提高效率. 但是,在py ...
- python单线程,多线程和协程速度对比
在某些应用场景下,想要提高python的并发能力,可以使用多线程,或者协程.比如网络爬虫,数据库操作等一些IO密集型的操作.下面对比python单线程,多线程和协程在网络爬虫场景下的速度. 一,单线程 ...
随机推荐
- Linux学习记录--文件IO操作相关系统编程
文件IO操作相关系统编程 这里主要说两套IO操作接口,各自是: POSIX标准 read|write接口.函数定义在#include<unistd.h> ISO C标准 fread|fwr ...
- 数据库中的參照完整性(Foreign Key)
之前在项目中遇到了这样一个问题,我举得简单的样例来说明. 比方我们有两个表,一个表(department)存放的是部门的信息,比如部门id,部门名称等:还有一个表是员工表(staff),员工表里面肯定 ...
- 在PowerShell脚本中集成Microsoft Graph
作者:陈希章 发表于2017年4月23日 我旗帜鲜明地表态,我很喜欢PowerShell,相比较于此前的Cmd Shell,它有一些重大的创新,例如基于.NET的类型系统,以及管道.模块的概念等等.那 ...
- 中国版Office 365 应用程序注册
作者:陈希章 发表于 2017年3月23日 中国版Office 365是由世纪互联进行运营的一个云服务,单纯从技术角度来看的话,它基本保持了与国际版的同步.但是由于两个版本本质上是完全独立的,其中最关 ...
- 最受Java开发者青睐的Java应用服务器 —— Tomcat
Tomcat 是一个小型的轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试 JSP 程序的首选.今天,就一起来了解下 Tomcat. Java 应用服务器 Tomc ...
- 通过gitbub桌面工具同步
1.先创建目录,和选择路径 2.commit -> sync 3. cd ~/.ssh 查看公钥 在github 添加公钥. 4. 克隆文件git clone git@github.con:cu ...
- solr6.5搭建以及使用经验
首先搭建环境为Linux 6.5 64位 jdk1.7 将webapp目录复制到tomcat下的webapps目录下 可以修改文件夹名为solr(这个自己随意定义,项目名而已) 在tomcat目录下 ...
- java 正则学习
前言 在网上找了许多关于正则解析 URL,结果不是很满意,所以自己学习正则: java url 那么解析 url 的代码如下: import java.util.regex.Matcher; impo ...
- jemeter——badboy导入的jmx文件自带元件解析
线程组设置与解析 含义:1秒启动100个线程,每个线程循环调用20次请求 (包括FTP请求.Java请求.http请求,根据你提交的请求而定) delay thread creation until ...
- python for循环巧妙运用(迭代、列表生成式)
200 ? "200px" : this.width)!important;} --> 介绍 我们可以通过for循环来迭代list.tuple.dict.set.字符串,di ...