zoukankan      html  css  js  c++  java
  • python 多线程

    什么是线程:

    在一个进程中,默认就有一个线程。将进程比喻成工厂车间的话,线程就相当于车间里的一条流水线。进程负责将资源整合到一起,而线程才是cpu上面的执行单位。

    多线程:

    一个进程中存在多个线程,多个线程共享该进程中的地址空间,相当于车间内的多条流水线,共享车间内的所有资源。

    进程和线程的区别:

    线程共享创建它的进程的地址空间。而进程有自己单独的地址空间。

    线程共享其进程资源,而进程完全copy其父进程资源。

    进程中的线程与线程可以直接通信,进程必须依赖进程间通信与同级进程通信。

    创建线程的开销远远小于进程,不用重复开辟内存空间。

    开启线程的两种方式:

    #方式一
    from threading import Thread
    def talk():
        print("%s is running"%os.getpid())
    if __name__ == '__main__':
        t = Thread(target=talk)
        t.start()
        print('')
    
    #方式二
    from threading import Thread
    import os
    class MyThread(Thread):
        def __init__(self,name):
            super().__init__()
            self.name = name
        def run(self):
            print("pid %s name [%s] is running"%(os.getpid(),self.name))
    if __name__ == '__main__':
        t = MyThread("egon")
        t.start()
        print("",os.getpid())
    创建线程的两种方式

    同一进程下开启多线程和多进程的区别:

    from multiprocessing import Process
    from threading import Thread
    def talk():
        start = time.time()
        print("%s is running"%os.getpid())
        print(time.time()-start)
    if __name__ == '__main__':
        #多进程,每个进程都有不同的ip
        t1 = Process(target=talk)
        t2 = Process(target=talk)
        t3 = Process(target=talk)
        t1.start()
        t2.start()
        t3.start()
        #多线程,每个线程的ip都和主线程一样
        t4 = Thread(target=talk)
        t5 = Thread(target=talk)
        t6 = Thread(target=talk)
        t4.start()
        t5.start()
        t6.start()
        print('',os.getpid())
    View Code

    练习:

    #服务端
    import threading
    from socket import *
    phone = socket(AF_INET,SOCK_STREAM)
    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    phone.bind(("192.168.19.115",8888))
    phone.listen(5)
    def talk(conn,addr):
        while True:
            try:
                data = conn.recv(1024)
                if not data:break
                conn.send(data.upper())
            except Exception:
                break
        conn.close()
    if __name__ == '__main__':
        while True:
            conn,addr = phone.accept()
            p = threading.Thread(target=talk,args=(conn,addr))
            p.start()
    #客户端
    from socket import *
    c = socket(AF_INET,SOCK_STREAM)
    c.connect(('192.168.19.115',8888))
    
    while True:
        msg = input(">>>:".strip())
        if not msg:continue
        c.send(msg.encode("utf-8"))
        data = c.recv(1024)
        print(data.decode('utf-8'))
    c.close()
    多线程实现并发
    from threading import Thread
    input_lis = []
    format_lis = []
    def talk():
        while True:
            msg = input(">>>:").strip()
            if not msg:continue
            input_lis.append(msg)
    def format():
        while True:
            if input_lis:
                res = input_lis.pop()
                format_lis.append(res.upper())
    def save():
        with open("db.txt",'a')as f:
            while True:
                if format_lis:
                    f.write("%s
    "%(format_lis.pop()))
                    f.flush()
    if __name__ == '__main__':
        t1 = Thread(target=talk)
        t2 = Thread(target=format)
        t3 = Thread(target=save)
    
        t1.start()
        t2.start()
        t3.start()
    模拟文件存储的过程

    线程的其它属性和方法:

    from threading import Thread,currentThread,activeCount
    import os,time,threading
    def talk():
        print("%s is running "%(currentThread().getName()))
    if __name__ == '__main__':
        t = Thread(target=talk)
        t = Thread(target=talk,name = "egon")
    
        t.start()
        print(t.name)#线程名
        print(t.getName())
        print(t.is_alive())
        print(currentThread().getName())#默认线程名
        print(threading.enumerate())#返回一个列表,同activeCount
        time.sleep(3)
        print(t.is_alive())#是否存活
        print("",activeCount())#个数
    其它属性和方法

    守护线程:


    无论是守护进程还是守护线程,都要遵循:守护进程(线程)会随着主进程(线程)运行结束而销毁。

    对进程来说:运行结束就是主进程代码运行结束

    对线程来说:运行结束必须等到所有的非守护线程运行结束后,主线程才算运行结束,因为主线程的结束以为这该进程的结束,进程的整体资源都将被回收。

    from threading import Thread,currentThread
    import time
    def talk1():
        time.sleep(10)#这里如果是小于或等于非守护进程的睡眠时间,将会执行下面代码
        print("%s is running"%currentThread().getName())#10秒时间足以让主线程和非守护线程执行结束,这句不会打印,随着主线程结束而结束
    def talk2():
        time.sleep(2)
        print("%s is running"%currentThread().getName())
    if __name__ == '__main__':
        t1 = Thread(target=talk1)
        t2 = Thread(target=talk2)
        t1.daemon = True
        t1.start()
        t2.start()
        print('主程序执行完成')#守护线程随着主线程的结束而结束,注意主线程是当所有的非守护线程结束后才会结束

    全局解释锁GIL:

    GIL的本质还是一把互斥锁,所有的互斥锁的本质都是一样,那就是将并发转成串行,以此来控制同一时间内共享数据只能被一个任务修改,从而保护数据的安全性。

    保护不同的数据安全,就应该加不同的锁

    GIL是把同一进程内,多个线程争抢一把锁,保证同一时刻只有一个线程在运行

    在线程执行过程中与I/O,运行时间过长的时候会强制释放GUL供其他线程使用。知道该线程再次抢到GUL,基于上次继续运行。

    from threading import Thread,Lock
    import time
    n = 100
    def work():
        global n
        tem = n
        time.sleep(0.5)
        n = tem-1
    if __name__ == '__main__':
        mutex = Lock()
        t_lis = []
        s = time.time()
        for i in range(100):
            t = Thread(target=work)
            t_lis.append(t)
            t.start()
        for t in t_lis:
            t.join()
        print("%s:%s"%(time.time()-s,n))
        # 0.5403599739074707:99执行了100次但是结果是99,出现数据错乱
    
    
    from threading import Thread,Lock
    import time
    n = 100
    def work():
        mutex.acquire()
        global n
        tem = n
        time.sleep(0.5)
        n = tem-1
        mutex.release()
    if __name__ == '__main__':
        mutex = Lock()
        t_lis = []
        s = time.time()
        for i in range(100):
            t = Thread(target=work)
            t_lis.append(t)
            t.start()
        for t in t_lis:
            t.join()
        print("%s:%s"%(time.time()-s,n))
        #   50.05104112625122:0加上应用层互斥锁,运行时间长,数据安全
    View Code
  • 相关阅读:
    scrapy 项目搭建
    linux mysql -- ERROR! The server quit without updating PID file (/usr/local/mysql/data/localhost.localdomain.pid)
    linux 安装python 和pip
    转 Pycharm及python安装详细教程
    mysql在linux下的安装
    easyui datagrid动态修改editor时动态绑定combobox的数据
    easyui combobox 在datagrid中动态加载数据
    linux 安装tomcat
    CUBRID学习笔记23 关键字列表
    CUBRID学习笔记 22 插入数据
  • 原文地址:https://www.cnblogs.com/shengzhongqiu/p/7450144.html
Copyright © 2011-2022 走看看