zoukankan      html  css  js  c++  java
  • 网络编程之线程1

    一 线程的理论

     什么是线程:线程就是开启一个进程,而执行进程里任务的就是线程。在一个进程里面可以创建多个线程,也叫做多线程。

     每创建一个主进程,同时就会产生一个控制线程,来执行主进程里面的任务。而这个线程就叫做主线程。主线程是可以用了开辟其他的子线程的,分发多个子线程。子线程下面还可以再有子线程

     在一个进程中创建的多个线程都可以共享这个进程里面的资源。

     为什么线程的开销小:创建线程是不会产生单独的内存空间的,而是在他的进程里面直接就会产生。

      线程和进程之间的关系

          1 线程一定是寄托在进程里面的。

          2一个进程可以分发多个线程,线程是最小的执行单位

          3 进程和线程的切换,切换时操作系统操作的,

            4切换的操作者:

                             4,1 时间片:就是切换的时候停止的时间

                             4,2 I/O操作切换:I/O卡住时,是不会占用CPU的。

            4,3 优先级切换。

    二 线程和进程的区别

     区别1:在同一个进程下的多个线程是可以共享这个进程里面的资源的。

        进程之间都会有独立的内存空间的,他们之间没有人任何关系的。

     区别2:线程之间是可以直接访问他们共同进程下的数据并进行修改。

        而进程之间的访问是需要依赖于ipc的。

     区别3:线程的创建是不需要重新开启单独的内存空间的。

        每一个进程的产生,就会产生一个内存空间的。

     区别4:同一个进程下的多个线程之间是可以相互影响的

        进程之间是没有任何影响的。

     区别5:同一个进程下的多个线程修改数据,都会影响到其他线程的

        进程之间,修改数据对其他的进程是没有任何影响的

    三 为什么要用多线程

     多个任务在一个进程里面完成,那就必须在这个进程里面开启多个线程。

      1 多线程共享着一个进程的内存空间

      2 线程比进程更轻量级,而线程比进程更加容易的创建和撤销。创建一个线程的速度会比创建一个进程的速度快上10到100倍之间。

      3 如果多个线程都是CPU密集型时,并不能获得性能上的提升。拥有多线程允许任务之间互相重叠运行,从而加快程序的执行速度

      4 为了利用多核,开启多个线程比开启多个进程的开销要小的多。在同一时候,一个CPU只能执行一个线程,所以CPU有几核,就能同时执行几个线程(而在cpython中,这个并不能实用,因为在cpython中,一个进程里面只能让一个线程运行。)

     线程才是被CPU真正执行的,而在进程之间的线程是没有任何关系的。

    线程的详细介绍:http://www.cnblogs.com/linhaifeng/articles/7430082.html

    四 threading模块:开启子线程的模块

     Thread:开启子线程

     target:后面加上一个函数名

     args:传参数,以元组的格式传入

     格式:线程=threading.Thread(target=函数名,args=(参数,))

     strart:向操作系统发送开启线程的信息(启动线程)

    线程的创建方式:

    方式1:

    # import threading
    # import os
    # def work(n):
    #     print('%s is working %s'%(os.getpid(),n))
    #
    #
    # if __name__=='__main__':
    #     for i in range(10):
    #         t=threading.Thread(target=work,args=(i,))
    #         t.start()
    #     print('主线程》》》',os.getpid())
    

     方式2:

    import threading
    class Mythread(threading.Thread):
        def __init__(self,n):
            super().__init__()
            self.n=n
        def run(self):
            print('%s is working' % self.n)
    if __name__=='__main__':
        for i in range(10):
            t=Mythread(i)
            t.start()
            print('主线程》》》')
    

     在同一个进程下,子线程和主线程使用的是统一个pid

     join:等待线程执行结束

    import threading
    import os
    import time
    import random
    def work(n):
        time.sleep(random.random())
        print('%s is working %s'%(os.getpid(),n))
    
    if __name__=='__main__':
        for i in range(10):
            t=threading.Thread(target=work,args=(i,))
            t.start()
            t.join()
        print('主线程》》》',os.getpid())
    

     threading的其他使用方法:

      getName:获取线程名

      setName:设置线程名

      carrent_thread:获取当前的线程对象

      enumerate:查看当前活跃的线程对象,以列表的格式返回

      activeCount:查看当前活跃的线程数目

    import threading
    import os
    import time
    import random
    def work(n):
        time.sleep(random.random())
        print('%s is working %s'%(os.getpid(),n))  
        print(threading.current_thread().getName())     #获取当前线程名
    
    if __name__=='__main__':
        for i in range(10):
            t=threading.Thread(target=work,args=(i,))
            t.start()
            print(threading.enumerate())    #查看当前活跃的对象
            print(threading.activeCount())    #查看活跃的数目
        print('主线程》》》',os.getpid())
    

     线程执行完毕,被回收的时间长短是不一样的。

    守护线程:守护线程会在主线程执行结束后,自动的结束。

    主线程从执行的意义上来讲就是一个主进程,主线程的结束会在除守护线程执行结束后就会结束。

    daemon=True:创建守护线程

    import threading
    import os
    import time
    import random
    def work(n):
        print('%s is working %s'%(os.getpid(),n))
        time.sleep(random.random())
        print('%s is ending %s'%(os.getpid(),n))
    def foo(n):
        print('%s is fooing %s'%(os.getpid(),n))
        time.sleep(random.random())
        print('%s is ending %s'%(os.getpid(),n))
    
    if __name__=='__main__':
        t1=threading.Thread(target=work,args=(100,))
        t2=threading.Thread(target=foo,args=(200,))
        t1.daemon=True
        t1.start()
        t2.start()
        print('主线程》》》',os.getpid())
    

    守护线程等待非守护线程的结束是为了关闭进程。

    五 GIL(互斥锁)

     1 全局解释互斥锁:保证了数据的安全性。而GIL是cpython解释器的一种特性。

     2 互斥锁(mutex):限制了cpython中多个线程的执行数量。与cpython的内存管理有关。

     3 cpython中有一个回收机制,绑定的关系引用技术为0时,就会自动的回收调。

     一把互斥锁只能保证一类数据的安全性。

    import threading
    import time
    import random
    n=20
    def work():
        global n
        loak.acquire()
        time.sleep(random.random())
        n-=1
        loak.release()
    if __name__=='__main__':
        li=[]
        loak=threading.Lock()
        for i in range(20):
            t=threading.Thread(target=work)
            li.append(t)
            t.start()
        for t in li:
            t.join()
        print(n)
    

     假如不加上锁,结果会不一样,如下:

    import threading
    import time
    import random
    n=200
    def work():
        global n
        time.sleep(random.random())
        n-=1
    if __name__=='__main__':
        for i in range(200):
            t=threading.Thread(target=work)
            t.start()
        t.join()
        print(n)
    

     GIL锁只能保证cpython解释器中的代码安全,不能保证自己的代码安全性,如果想要保证自己代码的安全性,就需要给自己的代码加上一把互斥锁

      有了GIL锁,就能保证cpython中的进程中的多个线程一只能执行一个。

    对于计算密集型来说,在多核CPU下开启多个进程的效率比较高

    #使用线程进行计算密集型
    # import threading
    # import time
    # def work():
    #     a=1
    #     for i in range(1000000):
    #         a*=i
    # if __name__=='__main__':
    #     li=[]
    #     start = time.time()
    #     for i in range(100):
    #         t=threading.Thread(target=work)     #13.447768926620483
    #         li.append(t)
    #         t.start()
    #     for t in li:
    #         t.join()
    #     print(time.time() - start)
    
    
    # 使用进程实现计算密集型
    # import multiprocessing
    # import time
    # def work():
    #     a=1
    #     for i in range(1000000):
    #         a*=i
    # if __name__=='__main__':
    #     li=[]
    #     start = time.time()
    #     for i in range(100):
    #         t=multiprocessing.Process(target=work)    #8.421481609344482
    #         li.append(t)
    #         t.start()
    #     for t in li:
    #         t.join()
    #     print(time.time() - start)
    

    对于IO密集型来说,多核CPU和单核CPU的效果是一样的,开启多线程的效率会比开启多进程的效率要高,并且还能保证数据的安全性。

    #使用线程进行IO密集型
    # import threading
    # import time
    # def work():
    #     time.sleep(2)
    # if __name__=='__main__':
    #     li=[]
    #     start = time.time()
    #     for i in range(10):
    #         t=threading.Thread(target=work)     #2.0028274059295654
    #         li.append(t)
    #         t.start()
    #     for t in li:
    #         t.join()
    #     print(time.time() - start)
    
    
    # 使用进程实现IO密集型
    # import multiprocessing
    # import time
    # def work():
    #     time.sleep(2)
    # if __name__=='__main__':
    #     li=[]
    #     start = time.time()
    #     for i in range(10):
    #         t=multiprocessing.Process(target=work)    #2.953113079071045
    #         li.append(t)
    #         t.start()
    #     for t in li:
    #         t.join()
    #     print(time.time() - start)
    
  • 相关阅读:
    利用CMD查看系统硬件信息
    固定资产分类(仅供参考 2005年),
    批量查询数据表的标识值的方法
    安装完office2016 64位后,在安装visio时,报错,无法安装,
    安装office2016 64位时提示64位与32位的office程序不兼容,在系统是64位的情况下,由于应用的需要,必须装64位的office,怎么办
    web.config文件详解
    master..xp_fileexist
    IE11快捷键 双击没反应的解决办法
    Grading
    今年第一个扶贫日
  • 原文地址:https://www.cnblogs.com/fangjie0410/p/7663029.html
Copyright © 2011-2022 走看看