python-高级编程-03
【多进程与多线程】
调度 : 在传统计算机操作系统中 cpu的调度的基本单位是进程,随着线程的引入,线程变成操作系统的最小调度单位
而进程是作为资源的拥有单位。
并行:由于线程的引入 原先一个进程只能有一个并发 现在一个进程可以有多个线程并行执行,
早起的httpserver 都是通过线程来解决服务器的并发 比起之前用fork子进程来处理并发效率有很大的提升。
这一切得益于线程可以用进程更低的代价实现并发。
共享 :一般linux线程会让线程继承或共享如下资源
。进程的共有数据内存
。 进程所打开的文件描述符
。 信号的处理器
。 进程用户的ID和进程组ID
隔离:
。线程ID ,在linux中 线程和进程共享ID空间
。寄存器的值
。线程的栈
。 优先级 linux的系统设计使得线程和进程除了在某些资源的共享和隔离有差异外,几乎是一视同仁的,他们可以有不同观点priority
我们在选择多进程还是多线程的时候需要根据业务场景使用。他们特性就是共享和隔离的区别。
【Linux的进程】
Linux在linus设计的时候的定位就是一个多任务的操作系统,从linux出的第一个版本的时候 就有了 进程的概念,
线程的产生是为了解决并发问题,线程的定位也就是更小更轻的进程
一些问题:
为什么不能一味的开线程解决并发问题?
#线程的上下文切换所带来的消耗,开的线程越多,在上下文切换过程中消耗就越大,核心就是内存根不上cpu的速度。
上下文切换: 在cpu还是单核的时候,计算机操作系统就已经实现了多任务系统,但是你要知道 单核的cpu在同一时间段内
只能执行某一个进程的某一个指令,为了达到多任务的执行效果,linux把cpu的时间切成大小不到等的时间
片,通过内核调度算法,让进程一个个上去跑,由于切换时间片的时间非常短,在我们人类看来 计算机在同时执行多个程序。
那么这个是如果实现的呢,如果程序到了时间片结束之后还没有完成它的工作,那么操作系统会把这个程序,以及其依赖的数据
都保存在内存里,然后回到进程的队列里。保存现场是需要代价的,这将极大的影响cpu的分支预测,影响系统性能,
所以频繁的上下文切换,是我们及其避免的。
【协程】
协程就是用户自己在进程中控制多任务的栈,尽可能的不让进程由于外部中断或者IO的等待丧失CPU调度的时间片,从而在进程内部实现并发。
【内存与守护进程】
程序运行时的内存,也就是我们在用户状态能看到的内存地址,都不是物理内存的地址,现代操作系统都会在物理内存上做一层,内存映射,每个
进程内的内存空间都是独立的
守护进程的特点:
1 后台运行,也不占用conscle的前面 也就是bash里运行程序后面加个&
2 成为 process group leader 守护进程的父进程是init的那个进程
3 成为 session leader 一个ssh登陆会启动一个bash bash会fork很多子进程,这些进程轮流接受tty输出,这都是一个session session leader就是一队进程的父进程
4 fork 一次到两次 因为linux父进程只对子进程负责,fork两次可以保证不影响正在执行的程序,直接交给init
5 chdir到/ 防止占用别的路径的 working dir的id 导致block不能
6 需要重置umask 方式后续子进程继承非默认umask造成不可控问题
7 处理标准输入输出 错误输出(0,1,2) 重定向stdout stderr stdin 防止tty中断后的broken pipe信号
8 日志 输入重定向后,需要有办法反映内部情况
--关于僵尸进程--父进程派生出子进程 如果子进程挂了 但是一般进程 父进程会拿着子进程的pid 调用wait,如果父进程对子进程没有处理,这个这个时候就会变成僵尸进程
如果父进程也挂了init会回收僵尸进程 而僵尸进程存的就是僵尸进程退出的退出码。
【用python写一个守护进程】
#!/usr/bin/env python
#coding=utf-8
import os,sys
import time ''' 使用python写个守护进程
''' def daemonzie(stdin='/dev/null',stdout='/dev/null',stderr='/dev/null'):
try:
pid = os.fork()
if pid >0:
sys.exit(0) except OSError ,e:
sys.stderr.write("fork #2 failed (%d) %s\n "%(e.errno,e.strerror))
sys.exit(1) os.chdir('/')# chdir到/ 防止占用别的路径的 working dir的id 导致block不能
os.umask(0)#需要重置umask 方式后续子进程继承非默认umask造成不可控问题
os.setsid()#成为 process group leader 守护进程的父进程是init的那个进程 try:
pid = os.fork()
if pid >0:
sys.exit(0) except OSError,e:
sys.stderr.write("fork #2 failed (%d) %s\n " % (e.errno, e.strerror))
sys.exit(1) for i in sys.stdout,sys.stderr:i.flush()
si = open(stdin,'r+')
so = open(stdout,'a+')
se = open(stderr,'a+',0)
os.dup2(si.fileno(),sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdin.fileno())
os.dup2(se.fileno(), sys.stdin.fileno()) def main():
import time
sys.stdout.write('Daemon started with pid %s\n'%os.getpid())
sys.stdout.write('Daemon stdout output\n')
sys.stderr.write('Daemon stderr output\n')
c = 0
while 1:
sys.stdout.write('%d:%s\n'%(c,time.ctime()))
sys.stdout.flush()
c + c+1
time.sleep(1) if __name__ == '__main__':
daemonzie('/dev/null','/tmp/daemon_stdout.log','/tmp/daemon_error.log')
main()
说白了 我们写一个 while 1 :print 'xxxx' 这种其实就是守护进程的基础 我们需要对一些东西进行处理后 才能形成一个正常的守护进程
【多线程实例】
1>
#!/usr/bin/env python
#coding:utf-8 import thread def f(name):
#定义线程函数
print 'this is '+name if __name__ == '__maim__':
thread.start_new_thread(f,("thread1",))
while 1:
pass
2>
#/usr/bin/env python
#coding:utf-8 import threading class Th(threading.Thread):
def __init__(self,name):
threading.Thread.__init__(self)
self.t_name = name
def run(self):
print "this is " + self.t_name if __name__ == '__main__':
thread1= Th("Thread1")
thread1.start()
threading.Thread 类的可继承函数
getName() 获得线程对象名称
setName() 设置线程对象名称 join() 等待调用的线程件数后再运行的命令 setDaemin(bool)阻塞模式
True 父线程不等待子线程的结束
False 等待默认为等待
isDaemon() 判断子线程是否和父线程一起结束 即setDaemon() 设置的值
isAlive()判断线程是否在运行
import threading
import time class my_therad(threading.Thread):
def __init__(self,thread_name):
threading.Thread.__init__(self)
self.setName=(thread_name) def run(self):
print 'this is thread'+ self.getName()
for i in range(5):
time.sleep(1)
print(str(i))
print self.getName()+'is over' if __name__ == '__main__':
thread1 = my_therad('T1')
thread1.start()
#thread1.join()
print 'main thread is over'
这里如果加了join()
this is threadThread-1
0
1
2
3
4
Thread-1is over
main thread is over
如果没加
this is threadThread-1
main thread is over
0
1
2
3
4
Thread-1is over
加了join 主线程会等待子线程结束返回之后才会执行
-------------------------------------------------------------------
import threading
import time class my_therad(threading.Thread):
def __init__(self,thread_name):
threading.Thread.__init__(self)
self.setName=(thread_name) def run(self):
print 'this is thread'+ self.getName()
for i in range(5):
time.sleep(1)
print(str(i))
print self.getName()+'is over' if __name__ == '__main__':
thread1 = my_therad('T1')
thread1.setDaemon(True)
thread1.start()
#thread1.setDaemon(True)
#thread1.join()
print 'main thread is over'
如果setDaemon 在start之前那么 主线程不会等待子线程,直接结束了
输出:
起多个子线程
if __name__ == '__main__':
for i in range(3):
t = my_therad(str(i))
t.start()
print 'main thread is over'
【线程锁】
import threading import time class Th(threading.Thread):
def __init__(self,thread_name):
threading.Thread.__init__(self)
self.setName(thread_name) def run(self):
threadLock.acquire()
print "this is thread "+self.getName()
for i in range(3):
time.sleep(1)
print str(i)
print self.getName()+' is over'
threadLock.release() if __name__ == '__main__':
threadLock = threading.Lock()
thread1 = Th('Thread_1')
thread2 = Th('Thread_2')
thread1.start()
thread2.start()
如果加上锁输出就是这样
this is thread Thread_1
0
1
2
Thread_1 is over
this is thread Thread_2
0
1
2
Thread_2 is over
如果不加
this is thread Thread_1
this is thread Thread_2
0
0
1
1
2
Thread_2 is over
2
Thread_1 is over
在thread中 优先会让之前拿到锁的人去拿锁 这样可以保证cpu分支预测的成功率
=======================================================================================================
#!/usr/bin/env python
#coding:utf-8
#####################
# time:2017-08-11 #
#####################
'''
this class is Daemon class ''' import os,sys,time,atexit from signal import SIGTERM class Daemon():
def __init__(self,pidfile = 'nbmon.pid',stdin='/dev/null',stdout='nbmon.log',stderr ='nbmon.log'):
self.stdin = stdin
self.stdout =stdout
self.stderr = stderr
self.pidfile = pidfile def daeminize(self):
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError ,e:
sys.stderr.write("fork #1 failed:%d(%s)"(e.errno,e.strerror))
sys.exit(1) os.chdir('/')
os.setsid()
os.umask(0) try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError ,e:
sys.stderr.write("fork #2 failed:%d(%s)"(e.errno,e.strerror))
sys.exit(1) sys.stdout.flush()
sys.stderr.flush()
si= file(self.stdin,'r')
so= file(self.stdout,'a+')
se = file(self.stderr,'a+',0)
os.dup2(si.fileno(),sys.stdin.fileno())
os.dup2(si.fileno(),sys.stdout.fileno())
os.dup2(si.fileno(),sys.stderr.fileno())
atexit.regoster(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+'.write("%s\n"%pid)) def delpid(self):
os.remove(self.pidfile) def start(self):
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError,e:
pid = None if pid :
message = "pidfile %s alreadly exit,Daemon is running\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1) self.daemonize()
self.run() def stop(self):
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close except IOError:
pid = None if not pid:
message = "pidfile %s does not exitst,Daemon is running\n"
sys.stderr.write(message % self.pidfile)
return
try:
while 1:
os.kill(pid,STGTERM)
time.sleep(0.1)
except OSError,err:
err = str(err)
if err.find("No such process") > 0 :
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print srt(err)
sys.exit(1)
def restart(self):
self.stop()
self.start()
def run(self):
pass
#!/usr/bin/env python
#coding:utf-8 from daemon import Daemon
import socket
import time html= """HTTP/1.1 200 OK\r\nContent-Type: image/jpeg\r\nConnection: close\r\nContent-Length: """
html404 = """HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\nContent-Length: 13\r\n\r\n<h1>404 </h1>""" class agentD(Daemon):
def run(self):
listen_fd = socket.socket(socket.AF_INET,socket.SOCK_STREAM, 0)
listen_fd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_fd.bind(("0.0.0.0",9085))
listen_fd.listen(10)
while True:
conn,addr = listen_fd.accept()
print "coming",conn,addr
read_data = conn.recv(10000)
try:
pic_name = read_data.split(" ")[1][1:] print pic_name,'*********' with file(pic_name) as f:
pic_content = f.read()
lengths = len(pic_content)
print lengths,"####"
html_resp = html
html_resp += "%d\r\n\r\n" % (lengths)
print html_resp
html_resp += pic_content
except:
print "404 occur"
html_resp = html404
while len(html_resp)>0:
sent_cnt = conn.send(html_resp)
print "sent:",sent_cnt
html_resp = html_resp[sent_cnt:] conn.close() if __name__ == '__main__':
agentd = agentD(pidfile = 'agent.pid',stdout='agent.log',stderr ='agent.log')
agentd.run()
python-高级编程-03的更多相关文章
- python高级编程技巧
由python高级编程处学习 http://blog.sina.com.cn/s/blog_a89e19440101fb28.html Python列表解析语法[]和生成 器()语法类似 [expr ...
- python高级编程:有用的设计模式3
# -*- coding: utf-8 -*-__author__ = 'Administrator'#python高级编程:有用的设计模式#访问者:有助于将算法从数据结构中分离出来"&qu ...
- python高级编程:有用的设计模式2
# -*- coding: utf-8 -*- __author__ = 'Administrator' #python高级编程:有用的设计模式 #代理 """ 代理对一 ...
- python高级编程:有用的设计模式1
# -*- coding: utf-8 -*-__author__ = 'Administrator'#python高级编程:有用的设计模式#设计械是可复用的,某种程序上它对软件设计中觉问题提供的语言 ...
- python高级编程之选择好名称:完
由于时间关系,python高级编程不在放在这边进行学习了,如果需要的朋友可以看下面的网盘进行下载 # # -*- coding: utf-8 -*- # # python:2.x # __author ...
- python高级编程读书笔记(一)
python高级编程读书笔记(一) python 高级编程读书笔记,记录一下基础和高级用法 python2和python3兼容处理 使用sys模块使程序python2和python3兼容 import ...
- python高级编程之列表推导式
1. 一个简单的例子 在Python中,如果我们想修改列表中所有元素的值,可以使用 for 循环语句来实现. 例如,将一个列表中的每个元素都替换为它的平方: >>> L = [1, ...
- Python高级编程之生成器(Generator)与coroutine(二):coroutine介绍
原创作品,转载请注明出处:点我 上一篇文章Python高级编程之生成器(Generator)与coroutine(一):Generator中,我们介绍了什么是Generator,以及写了几个使用Gen ...
- Python高级编程-Python一切皆对象
Python高级编程-Python一切皆对象 Python3高级核心技术97讲 笔记 1. Python一切皆对象 1.1 函数和类也是对象,属于Python的一等公民 ""&qu ...
- 第三章:Python高级编程-深入类和对象
第三章:Python高级编程-深入类和对象 Python3高级核心技术97讲 笔记 3.1 鸭子类型和多态 """ 当看到一直鸟走起来像鸭子.游泳起来像鸭子.叫起来像鸭子 ...
随机推荐
- 织梦后台上传mp4视频不显示
include/dialog/select_media.php ,约185行, 把(rm|rmvb) 改为(rm|mp4|rmvb)
- Object-C反射读取实体属性和值
举例: 首先定义TestModel如下: @interface TestModel : NSObject @property (nonatomic, strong) NSString *name; @ ...
- ArcGIS Server 10.1发布GP服务
ArcGIS Server 10.1发布GP服务 ArcGIS Server 10.1发布GP服务确实更简单了,只是刚使用不怎么习惯.ArcGIS Server 10.1发布GP服务需要先在ArcCa ...
- MVC4学习之官方教程中迁移版本库报错
因工作需要,学习MVC4,但是微软官方教程中迁移版本库步骤在本地测试报错 官方教程地址:http://www.asp.net/mvc/overview/older-versions/getting-s ...
- Netbackup驱动器常用命令vmoprcmd
1.vmoprcmd vmoprcmd – 对驱动器执行操作员功能 大纲 vmoprcmd -devmon [pr | ds | hs] [-h device_host] default_operat ...
- Connectivity
6492: Connectivity 时间限制: 1 Sec 内存限制: 128 MB提交: 118 解决: 28[提交][状态][讨论版][命题人:admin] 题目描述 There are N ...
- 2018.5.13 oracle遇到的问题
安装Oracle 11g 出现交换空间不够 在计算机那里右键打开属性进入高级系统设置然后找到第一个设置找到高级然后更改一下自定义范围(云服务器是16-10000) 然后确定 完成了. 快安装结束之后显 ...
- 查看nvidia的GPU
nvidia-smi就可以查看,可以看到进程的占用率,可以kill杀掉进程 注意这里的-前后都不要空格,连起来写
- C语言中math.h中常用的函数
1.绝对值 ①函数原型: int abs(int x); 函数功能: 求整数x的绝对值 int number=-1234; abs(number); ②函数原型:double fabs(double ...
- cocos2d-x之CCCardinalSplineBy
CCCardinalSplineBy概念 这个类是样条曲线动作,其创建函数CCCardinalSplineBy::create(float duration, cocos2d::CCPointArra ...