Mezhou

多线程、多进程


进程:一个进程就是一个程序。
线程:线程就是进程里面最小的执行单元。
线程是在进程里面的,干活的还是线程。
一个进程里面最少有一个线程,可以有多个线程
每个线程之间都是互相独立的
没有真正意义上的并发,你的电脑的cpu是几核的,那么最多只能同时运行几个任务。

串行:

1 import threading,time
2 def run():
3     time.sleep(5)
4     print(\'哈哈哈哈\')
7 for i in range(5):#串行
8     run()

 

多线程

复制代码
1 import threading,time
3 def run(name):
4     time.sleep(5)
5     print(\'【%s】哈哈哈哈\'%name)
6 for i in range(10):
7     t=threading.Thread(target=run,args=(i,))#args传元组时,如果只有一个参数必须加一个逗号
8     t.start()
复制代码
import threading
import hashlib
import requests

def md5(msg):
    msg = str(msg)
    m = hashlib.md5(msg.encode())
    return m.hexdigest()

def down_load_pic(url):
    print(\'图片下载开始\',url)
    r = requests.get(url)
    file_name = md5(url)+\'.png\'
    with open(file_name, \'wb\') as fw:
        fw.write(r.content)
        print(\'%s图片下载完成\'%file_name)

urls = [\'https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140\', \'https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140\',
        \'https://q4.qlogo.cn/g?b=qq&nk=1473732204&s=140\', \'https://q4.qlogo.cn/g?b=qq&nk=974757912&s=140\']
for url in urls:
        t = threading.Thread(target=down_load_pic,args=[url])
        t.start()
while threading.active_count()!=1:
    pass
print(\'所有照片已下载完成!\')

 

获取不到返回值怎么办?return回来的返回值获取不到

复制代码
import threading,time
all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
def run(name):
    time.sleep(5)
    print(\'【%s】哈哈哈哈\'%name)
    name =\'hhj\'+name
    all_res.append(name)
    print(all_res)
for i in range(10):
    t=threading.Thread(target=run,args=(str(i),))#args要传元组,如果只有一个参数必须加一个逗号
    t.start()
复制代码

等待子线程都执行完成再计时和返回字典:

方法1:

复制代码
import threading,time
all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
def run(name):
    time.sleep(5)
    print(\'【%s】哈哈哈哈\'%name)
    name =\'hhj\'+name
    all_res.append(name)

for i in range(10):
    t=threading.Thread(target=run,args=(str(i),))
    t.start()
#主线程,线程之间是相互独立的
while threading.active_count()!=1:#判断当前活动的线程是几个,如果是1的话,说明子线程已经执行完成了
    pass
end = time.time()
print(end-start)
print(\'sleep之后的。。\',all_res)
复制代码

 

还有一种方法:

# t.join()#等待

 

复制代码
 1 import threading,time
 2 all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
 3 def run(name):
 4     time.sleep(5)
 5     print(\'【%s】哈哈哈哈\'%name)
 6     name =\'hhj\'+name
 7     all_res.append(name)
 8 
 9 for i in range(10):
10     t=threading.Thread(target=run,args=(str(i),))
11     threads.append(t)
12     t.start()
13 for t in threads:#再统一去等待子线程执行结束
14     t.join()#等待
15 end = time.time()
16 print(end-start)
17 print(\'sleep之后的。。\',all_res)

复制代码

 

查看线程的id

复制代码
 1 import threading,time
 2 all_res =[]#想要获取返回值就用一个字典或者列表。这是用来存储函数结果的。
 3 def run(name):
 4     print(\'子线程执行的。。\',threading.current_thread())
 5     time.sleep(5)
 6     print(\'【%s】哈哈哈哈\'%name)
 7     name =\'hhj\'+name
 8     all_res.append(name)
 9 
10 for i in range(3):
11     t=threading.Thread(target=run,args=(str(i),))
12     threads.append(t)
13     t.start()
14 for t in threads:#再统一去等待子线程执行结束
15     t.join()#等待
16 
17 print(\'主线程执行的。。\', threading.current_thread())
18 
19 end = time.time()
20 print(end-start)
21 print(\'sleep之后的。。\',all_res)
复制代码

 

守护线程:

复制代码
 1 #守护线程
 2 #守护线程就是和秦始皇陪葬的人一样
 3 #主线程就是秦始皇
 4 #子线程就是陪葬的人
 5 import threading
 6 import time
 7 def run():
 8     time.sleep(9)
 9     print(\'run...\')
10 for i in range(10):
11     t = threading.Thread(target=run)
12     t.setDaemon(True)#设置子线程成为一个守护线程
13     t.start()
14 print(\'over.\')
复制代码

注释掉守护线程:

复制代码
 1 import threading
 2 import time
 3 def run():
 4     time.sleep(9)
 5     print(\'run...\')
 6 for i in range(10):
 7     t = threading.Thread(target=run)
 8     # t.setDaemon(True)#设置子线程成为一个守护线程
 9     t.start()
10 print(\'over.\')
复制代码

没有真正意义上的并发,你的电脑的cpu是几核的,那么最多只能同时运行几个任务。

python里面的多线程,是利用不了多核cpu的,只能利用一个核心的cpu

有些情况下,你用多线程的时候会发现它比单线程速度还慢。

 查看电脑的cpu是几核的:

锁:

import threading
count = 0
lock = threading.Lock()

def add():
    global count
    for i in range(1000000):
    #法1
        # lock.acquire()#加锁,线程安全;多线程的时候需要加锁,否则多个人修改同一条数据会报错
        # count += 1
        # lock.release()
    # 法2
        with lock:#自动加锁自动释放
            count += 1
for i in range(2):
    t = threading.Thread(target=add)
    t.start()
while threading.active_count() != 1:
    pass
print(count)

 线程池

安装threadpool模块(pip install threadpool)
复制代码
import threadpool,requests,pymongo
client = pymongo.MongoClient(host=\'ip\',port=27017)
table = client[\'likun\'][\'qq_group_likun\']
all_qq = [i.get(\'qq\') for i in table.find()]

url = \'http://q4.qlogo.cn/g?b=qq&nk=%s&s=140\'
def down_img(qq_num):
    res = requests.get(url%qq_num).content
    with open(\'%s.jpg\'%qq_num,\'wb\') as fw:
        fw.write(res)
pool = threadpool.ThreadPool(200)#线程池的大小
all_requests = threadpool.makeRequests(down_img,all_qq)#分配数据
for r in all_requests:
    pool.putRequest(r)#发请求
#[pool.putRequest(r) for r in all_requests]#同上两行
pool.wait()#等待所有的线程运行完
print(\'done,下载完成!\')
复制代码

 

import threadpool
import threading
import hashlib
import requests
import os

def md5(msg):
    msg = str(msg)
    m = hashlib.md5(msg.encode())
    return m.hexdigest()

def down_load_pics(url):
    print(threading.current_thread())
    print(\'图片下载开始\',url)
    r = requests.get(url)
    pic_name = md5(url)+\'.jpg\'
    if not os.path.exists(\'pics\'):
        os.system(\'mkdir pics\')
    pic_name = os.path.join(\'pics\',pic_name)
    with open(pic_name,\'wb\') as fw:
        fw.write(r.content)

urls=[\'https://q4.qlogo.cn/g?b=qq&nk=475566024&s=140\', \'https://q4.qlogo.cn/g?b=qq&nk=616745045&s=140\',
        \'https://q4.qlogo.cn/g?b=qq&nk=1473732204&s=140\', \'https://q4.qlogo.cn/g?b=qq&nk=974757912&s=140\']

pool = threadpool.ThreadPool(2)
reqs = threadpool.makeRequests(down_load_pics,urls)#传方法名和一个列表
for req in reqs:
    pool.putRequest(req)
pool.wait()
print(\'下载完成\')

 

进程(进程里可以启动线程,也要加锁)

import multiprocessing
import time

def make_money(name):
    print(\'%s开始挣钱\'%name)
    time.sleep(2)

def start_process():
    p = multiprocessing.Process(target=make_money,args=[\'zjr\'])
    p.start()

if __name__ == "__main__":
    start_process()

锁、多进程中加多线程

import multiprocessing
import time
import threading
# lock = multiprocessing.Lock()
def test():
    print(\'多线程\')

def make_money(name):
    for i in range(10):
        t = threading.Thread(target=test)#多进程中加多线程
        t.start()
    print(\'%s开始挣钱\'%name)
    time.sleep(2)

def start_process():
    for i in range(5):
        p = multiprocessing.Process(target=make_money,args=[\'zjr\'])
        p.start()
    print(multiprocessing.active_children())
    while len(multiprocessing.active_children()) != 1:
        pass
    print(\'运行结束\')

if __name__ == "__main__":
    start_process()

 

进程池

复制代码
 1 from multiprocessing import Process, Pool, active_children
 2 import pymongo,requests
 3 client = pymongo.MongoClient(host=\'118.11.3.40\',port=27017)
 4 table = client[\'likun\'][\'qq_group_likun\']
 5 all_qq = [i.get(\'qq\') for i in table.find()]
 6 
 7 url = \'http://q4.qlogo.cn/g?b=qq&nk=%s&s=140\'
 8 def down_img(qq_num):
 9     res = requests.get(url%qq_num).content
10     with open(\'%s.jpg\'%qq_num,\'wb\') as fw:
11         fw.write(res)
12 if __name__==\'__main__\':#必须写在这句底下,否则多进程用不了
13     for qq in all_qq:
14         # p = Process(target=down_img,args=(qq,))
15         # p.start()
16      # print(active_children())#打印活动的进程数
17         pool = Pool(5)#指定进程池的大小
18         list(pool.map(down_img,all_qq))#运行,使用进程池
19         #map是个生成器
复制代码

 

什么时候用多线程,什么时候用多进程?

cpu密集型任务:
消耗cpu比较多
排序、运算。。

io密集型任务
input/output
写文件、读文件
上传、下载
python的多线程是利用不了多核cpu的
全局解释器锁:GIL
多进程是可以利用多核cpu的


分类:

技术点:

相关文章: