python学习笔记(二十一)-- 进程、线程

1、进程VS线程

进程

  对于操作系统来说,一个任务就是一个进程。

  进程一个程序的执行实例就是一个进程,每一个进程提供执行程序所需的所有资源。

  一个进程包含一个主线程,0或者多个子线程。

线程

        线程是执行的最小单位。

        线程不分配自己的资源,所有线程共享进程的资源,线程之间互不影响。

线程的种类

        主线程

        子线程、

        守护线程

2、多线程

Python里面多线程不能利用多个CPU,它只能在一个CPU上运行。

Python多线程使用threading模块实现

import threading #线程模块
import time

def run(url):
    time.sleep(2)
    print(url)
    print('running...')
def eat():
    print('吃饭')

start_time = time.time()#程序开始运行时的时间戳

threads = []

for i in range(10):
    # 实例化一个线程,run是函数名
    t = threading.Thread(target=run,args=('http://www.baidu.com',)) # 一个参数一定加个逗号
    t.start()#启动这个线程
    threads.append(t)#把所有子进程加进threads列表

# for thread in threads:
#     thread.join()#使用join,主线程就会等待子线程执行结束再往下执行

#使用上面join的方式或者while循环的方式
# 让主线程等待子线程执行完成再执行下面的程序
while threading.active_count() != 1: #当线程数为1,才结束循环
    pass

print(threading.active_count()) #当前线程数

end_time = time.time()#程序结束时的时间戳
print('运行时间',end_time-start_time) #这个时间是主线程执行完代码的时候,不包含子线程执行时间

 多线程下载图片

import time ,requests, threading
from hashlib import md5
urls = [
    'http://www.178linux.com/wp-content/uploads/2018/02/5.jpg ',
    'http://img1.imgtn.bdimg.com/it/u=1139158180,2224775217&fm=11&gp=0.jpg ',
    'http://www.linuxidc.com/upload/2019_04/19041915053582.png ',
    'http://www.veryxue.com/file/upload/201905/09/201804031578.jpg ',
    'http://5b0988e595225.cdn.sohucs.com/images/20171209/8e81dcb041a9425c823daf6b6053e03b.jpg '
]

result = []

def down_load_picture(url):
    r = requests.get(url)
    file_name = md5(r.content).hexdigest()
    with open(file_name+'.jpg','wb') as fw:
        fw.write(r.content)
        result.append(file_name)
        print('[%s]下载完成'%file_name)

start_time = time.time()

for url in urls:
    t = threading.Thread(target=down_load_picture,args=(url,))
    t.start()
    print(result)#在这里打印不出来,因为还没有下载完成就走到这里了


while threading.active_count() != 1:
    pass

end_time = time.time()
run_time = end_time - start_time
print('下载时间是%s'%run_time)

3、守护线程

守护线程通过setDaemon(True)设置,守护线程只守护主线程。
当主线程运行完成,守护线程自动结束。

import threading,time

#守护线程 只能守护主线程
print('QQ上线啦!')

def conversation():
    print('聊天窗口,每天上班先聊2小时,正在聊...')
    time.sleep(20)
    print('聊完了')

for i in range(10):
    t = threading.Thread(target=conversation)
    t.setDaemon(True)#设置成守护线程,主线程运行完成,守护线程自动结束
    t.start()

time.sleep(1)
print('领导来了,退出QQ')

4、线程锁

多个线程操作同一个数据时,有可能会出问题,这个时候就需要把操作的数据加锁,操作完成后再解锁,这样同一时间就只有一个线程可以操作这块数据。

import threading

lock = threading.Lock()#实例化一把锁

sum = 0
def add():
    global sum
    with lock: #加锁
        sum += 1
    #也可以这样加锁
    # lock.acquire()#加锁
    # sum += 1
    # lock.release()#解锁

for i in range(10):
    t = threading.Thread(target=add)
    t.start()

while threading.active_count()!=1:
    pass

print(sum)

5、多进程

Python的多线程是不能利用多核CPU的,想要利用多核CPU,需要开启多进程。

import multiprocessing,threading,random

def multi_test():
    for i in range(5):
        t = threading.Thread(target=t_test)#开启线程,从随机数能看出开启了不同线程
        t.start()

def t_test():
    print("这是一个线程%s"%random.randint(1,10))

if __name__ == '__main__':
    for i in range(10): #循环10个进程,并调用循环开启线程的函数
        m = multiprocessing.Process(target=multi_test)
        m.start()

    while len(multiprocessing.active_children())!=1:
        pass

    print('结束')

6、线程池

可以使用线程池来批量启动线程,它可以自己管理线程数,最多启动设置的最大线程数,需要多少开启多少。如果线程池中线程数已满,这时有新的请求则会等待运行的线程结束后再执行新的线程。

import threadpool
import time

urls = [
    'http://www.178linux.com/wp-content/uploads/2018/02/5.jpg ',
    'http://img1.imgtn.bdimg.com/it/u=1139158180,2224775217&fm=11&gp=0.jpg ',
    'http://www.linuxidc.com/upload/2019_04/19041915053582.png ',
    'http://www.veryxue.com/file/upload/201905/09/201804031578.jpg ',
    'http://5b0988e595225.cdn.sohucs.com/images/20171209/8e81dcb041a9425c823daf6b6053e03b.jpg '
]

def test(url):
    time.sleep(2)
    print('test...',url)

pool = threadpool.ThreadPool(2)#指定线程池大小,这是最大值,用多少会启动多少
reqs = threadpool.makeRequests(test,urls)#第一个参数是函数名,第二个参数是所有的数据

[pool.putRequest(r) for r in reqs]
# for r in reqs:
#     pool.putRequest(r)

pool.wait()#等待子线程执行结束


print('over!')

7、进程池

批量开启进程,自己对进程数进行管理,同线程池一样。

import multiprocessing
import os


def worker(msg):
    print("%s开始执行,进程号为%d" % (msg, os.getpid()))


if __name__ == '__main__':

    po = multiprocessing.Pool(3)  # 定义一个进程池,最大进程数3
    for i in range(0, 10):
        # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
        # 每次循环将会用空闲出来的子进程去调用目标
        po.apply_async(func=worker, args=(i,))
    # 第一个func参数指定运行的函数,第二个args是参数,没有参数可以不写
    print("----start----")
    po.close()  # 关闭进程池,关闭后po不再接收新的请求
    po.join()  # 等待po中所有子进程执行完成,必须放在close语句之后
    print("-----end-----")
原文地址:https://www.cnblogs.com/yanyan-/p/10966079.html