zoukankan      html  css  js  c++  java
  • 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
     "%(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
     " % (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
    '%os.getpid())
        sys.stdout.write('Daemon stdout output
    ')
        sys.stderr.write('Daemon stderr output
    ')
        c = 0
        while 1:
            sys.stdout.write('%d:%s
    '%(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
    "%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
    "
                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
    "
                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
    Content-Type: image/jpeg
    Connection: close
    Content-Length: """
    html404 =  """HTTP/1.1 404 Not Found
    Content-Type: text/html
    Content-Length: 13
    
    <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
    
    " % (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()
    

      










  • 相关阅读:
    【转】final 关键字
    【转】安装Fiddler2+JsonViewer插件
    【转】SAP SD定价技术分析
    【转】SAP PP 顾问面试考试试题及资料
    【转】Hibernate数据过滤
    【转】与计划有关的生产数据
    【转】销售凭证类别
    将MyEclipse中的项目导入到Eclipse中报错的解决放法,将项目打war包部署服务器
    查看Android下生成的.db数据库
    删除快速启动栏的快捷方式 pplive
  • 原文地址:https://www.cnblogs.com/nerdlerss/p/7256142.html
Copyright © 2011-2022 走看看