1,一个cpu一次只能执行一个任务, 多个cpu同时可以执行多个任务 2,一个cpu一次只能执行一个进程, 其他进程处于非运行状态 3,进程里包含的执行单元叫线程,一个进程可以包含多个线程 4,一个进程的内存空间是共享的,每个进程里的线程都可以使用这个共享空间 5,一个线程在使用这个共享空间的时候, 其它的线程必须等待(阻塞状态) 6,互斥锁作用就是防止多个线程同时使用这块内存空间, 先使用的线程会将空间上锁, 其它的线程处于等待状态, 等锁开了才能进 7,进程: 表示程序的一次执行 8,线程:CPU运算的基本调度单位 9,GIL(全局锁):Python里的执行通行证, 而且只有一个, 拿到通行证的线程就可以进入CPU执行任务, 没有GIL的线程就不能执行任务 10, Python的多线程适用于大量密集的I/O处理 11,Python的多进程适用于大量的密集并行计算
添加线程 threading.Thread(target, args) 使用threading.Thread()新建一个线程, target是需要执行的函数, args是需要传入该函数的参数, args接受一个tuple, 即使只有一个参数 也需要写成(x,)形式 import threading def thread_job(): print('1111') def main(): thread = threading.Thread(target=thread_job,) # 添加一个线程 thread.start() # 开始该线程 if __name__ == '__main__': main()
线程阻塞:join join()的作用是调用该线程时, 等待该线程完成之后在继续往下执行 join通常用于主线程与子线程之间, 主线程等待子线程运行完毕后在继续执行, 避免子程序和主程序同时执行, 子程序还没有运行完的时候就已经运行结束 import threading import time def T1_job(): print('T1 start\n') for i in range(10): time.sleep(10) print('T1 finish\n') def T2_job(): print('T2 start\n') print('T2 finish\n') def main(): thread1 = threading.Thread(target=T1_job, name='T1') thread2 = threading.Thread(target=T2_job, name='T2') thread1.start() thread1.join() # 等待执行thread1完成后才能进行下一步-主程序 thread2.start() thread2.join() print('all done') if __name__ == '__main__': main()
Queue(队列对象) Queue是Python中的标准库, 可以直接import Queue引用, 队列是线程间最常用的交换数据的形式 Python下多线程的思考 对于资源, 加锁是个重要的环节, 因为Python原生的list ,dict等, 都是 not thread safe的, 而Queue,是线程安全的, 因此在满足使用条件下, 建议使用队列 1, 初始化: class.Queue.Queue(maxsize) FIFO先进先出 2, 包中国的常用方法: Queue.qsize()返回队列的大小 Queue.empty()如果队列为空, 返回True,反之False Queue.full()如果队列满了, 返回True,反之False Queue.full与maxsize大小对应 Queue.get([block[, timeout]])获取队列, timeout等待时间 3, 创建一个"队列"对象 import Queue myqueue = Queue.Queue(maxsize=10) 4,将一个值放入队列中 myqueue.put(10) 5,将一个值从队列中取出 myqueue.get()
import threading
from queue import Queue
"""
# Queue是python标准库中的线程安全的队列(FIFO)实现, 提供了一个适用于多线程编程的先进先出的数据结构,即队列.
# Queue是一种先进先出的数据结构, 一般来说读数据都从Queue头读, 写数据都从Queue尾写入
# """
def job(l,q):
for i in range(len(l)):
l[i] = l[i] ** 2
q.put(l) # 线程中, return获取的值无法提取, 需要放入q中
def multithreading():
q = Queue() # 队列
threads = [] # 全部线程
data = [[1, 2, 3], [3, 4, 5], [4, 4, 4], [5, 5, 5]]
for i in range(4):
t = threading.Thread(target=job, args=(data[i], q)) # 4个线程来执行job函数
t.start()
threads.append(t) # 当前线程加入全部线程中
# 对主线程的每一个线程都执行join()
for thread in threads:
thread.join()
results = [] # 保存结果
for _ in range(4):
results.append(q.get()) # 从q中取值, 每次只能按顺序拿出一个值
print(results)
if __name__ == '__main__':
multithreading()
""" 线程锁:Lock lock在不同线程使用同一共享内存时, 能够确保线程之间互不影响 使用lock的方法是: 在每个线程执行运算修改共享内存之前执行lock.acquire()将共享内存上锁, 确保当前线程执行时, 内存不会被其他线程访问; 执行运算完毕后使用lock.release() 将锁关闭, 保证其他的线程可以使用该共享内存. lock.acquire()和lock.release()必须成对出现 下面代码 将lock.acquire(), lock.release()注释掉后, 输出结果是混乱的, 加锁后, 输出结果按顺序执行 # """ def job1(): global A, lock lock.acquire() # 打开锁 for i in range(10): A += 1 time.sleep(2) print('job1', A) lock.release() # 关闭锁 def job2(): global A, lock lock.acquire() # 打开锁 for i in range(10): A += 10 time.sleep(2) print('job2', A) lock.release() # 关闭锁 if __name__ == '__main__': lock = threading.Lock() # lock锁 A = 0 t1 = threading.Thread(target=job1) t2 = threading.Thread(target=job2) t1.start() t2.start()
import threading from multiprocessing.dummy import Pool as ThreadPool """ 线程池有几种方法可以实现, 这里我们使用multiprocessing.dummy库 """ def job(i): print(i, '\n', threading.current_thread()) if __name__ == '__main__': pool = ThreadPool(4) # 创建一个包含4个线程的线程池 pool.map(job, range(12)) pool.close() # 关闭线程池的写入 pool.join() # 阻塞, 保证子线程运行完毕后在继续主进程