十一、多线程

一、多线程基础 

进程拥有资源(内存等),线程不拥有资源,共享进程的资源

同属于一个进程中的线程可以共享CPU分配的全部资源

多个线程的切换速度比多个进程快,消耗的资源也少。

多个线程可以并行地在多核CPU中执行。

进程是系统资源分配的基本单元

线程是CPU 调度和分配的基本单位

线程不拥有系统资源,但可以访问隶属于进程的资源

一个进程默认有一个线程

线程是由操作系统调用的

协程是由用户调用的 

"""
线程类:threading.Thread
线程任务:target
线程任务的参数:args
线程名:name
该举例1个进程,2个线程
""" import threading import time def music(user): for i in range(5): time.sleep(1) print(f'{user}正在听音乐{i}') print(f'{threading.current_thread().name}正在运行') def lol(user): for i in range(5): time.sleep(1) print(f'{user}正在玩LOL{i}') print(f'{threading.current_thread().name}正在运行') def main(): # 创建2个线程 t1 = threading.Thread(target=music, args=('小样儿',), name='线程1') t2 = threading.Thread(target=lol, kwargs={'user': '小样儿'}, name='线程2') # 启动线程 t1.start() t2.start() t1.join() # 阻塞 t2.join() print("程序结束!") if __name__ == '__main__': main()

二、多线程共享全局变量 

import threading

n = 100

def work1():
    global n
    for i in range(1000):
        n += 1

def work2():
    global n
    for i in range(1000):
        n += 1

if __name__ == '__main__':
    t1 = threading.Thread(target=work1)
    t2 = threading.Thread(target=work2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f'n:{n}')  # 2100

三、线程锁

根据以上例子,当线程并发次数多时,如range(100000)等,就会出错

因此需要线程锁,确保每次

import threading

n = 200000
lock = threading.Lock()

def work():
    global n
    for i in range(100000):
        lock.acquire()  # 关门上锁
        # with lock:  # 防止同时修改n
        n -= 1
        lock.release()  # 解锁

if __name__ == '__main__':
    t1 = threading.Thread(target=work)
    t2 = threading.Thread(target=work)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f'n:{n}')

 四、自定义线程类

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, user):
        super(MyThread, self).__init__()
        self.user = user

    def run(self):
        """线程启动的时候会调用此方法"""
        for i in range(5):
            time.sleep(1)
            print(f'{self.user}正在听音乐...')

if __name__ == '__main__':
    t = MyThread(user='小样儿')
    t.start()

五、线程池

import time
from concurrent.futures import ThreadPoolExecutor

def work(result):
    time.sleep(1)
    print("Hello!")
    return result

def main():
    thread_executor = ThreadPoolExecutor(max_workers=5)
    future = thread_executor.submit(work, "完成")
    print(future.done())
    time.sleep(2)
    print(future.done())
    print(future.result())

if __name__ == '__main__':
    main()

'''
False
Hello!
True
完成
'''

参考资料转自:https://www.cnblogs.com/hoojjack/p/10846010.html

六、第三方线程池(threadpool)

安装:pip  install threadpool

import time

import threadpool

def hi(s):
    print(f"hi,{s}
")
    time.sleep(2)

def main():
    start_time = time.time()
    thread_pool = threadpool.ThreadPool(2)
    reqs = threadpool.makeRequests(hi, ['a', 'b', 'c'])
    for req in reqs:
        thread_pool.putRequest(req)
    thread_pool.wait()  # 等待线程池中的所有线程执行完毕
    end_time = time.time()
    print(f'总共花费时间为:{end_time - start_time}')


if __name__ == '__main__':
    main()

'''
hi,a
hi,b
hi,c
总共花费时间为:4.006930828094482
'''

七、GIL锁

GIL: 中文全局“解释器”锁。锁的是谁利用CPU,锁不住代码

线程占用CPU: 无论是多核CPU,还是多CPU,同一间时间,只有一个线程在使用CPU

CPU密集型场景,不要用多线程,用了反而慢,原因是Python不能利用多核(GIL决定的)

IO密集型场景,使用多线程可以节省时间。因为IO不占用CPU,GIL锁影响不大。

原文地址:https://www.cnblogs.com/zhangjx2457/p/14129970.html