【多进程与多线程】

调度 : 在传统计算机操作系统中 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()

  


最新文章

  1. css实现自适应屏幕高度;
  2. 如何在SQLServer中处理每天四亿三千万记录
  3. ios category
  4. uglifyjs使用
  5. 1050 Moving Tables
  6. INNOBACKUPEX热备MYSQL数据
  7. asp 回发的时候样式变化
  8. 轻松学习Ionic (二) 为Android项目集成Crosswalk(更新官方命令行工具)
  9. WPF多线程问题
  10. 并发库应用之十 &amp; 多线程数据交换Exchanger应用
  11. CentOS搭建FTP服务
  12. luoguP4035
  13. python S2-45 漏洞利用工具
  14. Promise事件比timeout优先
  15. 洛谷P4551 最长异或路径
  16. sqler sql 转rest api 的docker 镜像构建(续)使用源码编译
  17. vue 自定义组件的自定义属性
  18. 5个经典的JavaScript面试题
  19. LoadRunner FAQ
  20. postgresql中终止正在执行的SQL语句

热门文章

  1. Hive的HQL(2)
  2. log4cxx安装使用
  3. GoAccess自动分割Nginx日志
  4. 洛谷 P1145 约瑟夫
  5. 2018.3.31 java中的递归
  6. cocos2dx lua 热更新方案的实现
  7. 浅谈 MySQL 中优化 SQL 语句查询常用的 30 种方法
  8. 03IO端口寻址和访问控制方式
  9. Java使用ResourceBundle类读取properties文件中文乱码的解决方案
  10. 【mac】【转发】Mac系统升级后,按大小写键没反应了,切换大小写的灯不亮了