python-线程与进程的理解;多线程

粗浅理解:

  • 程序: /bin/firefox是一个二进制程序, (eg:python, Java程序), 是一个真实存在的, 可以看到的实体;
  • 进程: 执行程序的过程中产生的一系列内容,(计算机给进程分配了内存, cpu等…)
  • 线程: 是执行进程

专业的总结:

  • 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,
    是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
  • 线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。
    是被系统独立调度和分派的基本单位。

1.创建线程

一个进程里面必然有一个主线程
操作线程的模块:
thread
threading

import _thread
import threading
import time

def job():
    print("这是一个需要执行的任务。。。。。")
    print("当前线程的个数:", threading.active_count() )
    print("当前线程的信息:", threading.current_thread())
    time.sleep(100)
if __name__ == '__main__':
    job()

2.实现多线程的方法

(1)第一种(不常用):

import threading
import time
import _thread
def job():
    print("这是一个需要执行的任务。。。。。")
    print("当前线程的个数:", threading.active_count() )
    print("当前线程的信息:", threading.current_thread())
    time.sleep(100)
if __name__ == '__main__':
    # c创建多线程时, 需要制定该线程执行的任务
    _thread.start_new_thread(job, ())
    _thread.start_new_thread(job, ())

    # job()
    while True:
        pass

(2)第二种:

import threading
import time
import _thread
def job():
    print("这是一个需要执行的任务。。。。。")
    print("当前线程的个数:", threading.active_count() )
    time.sleep(1)
    print("当前线程的信息:", threading.current_thread())

if __name__ == '__main__':
    # c创建多线程时, 需要制定该线程执行的任务
    t1 = threading.Thread(target=job )
    t2 = threading.Thread(target=job)
    t1.start()
    t2.start()
    print(threading.active_count())

    # 出现的问题: 主线程执行结束, 但是子线程还在运行。
    # 等待所有的子线程执行结束之后, 再执行主线程
    t1.join()
    t2.join()
    print("程序执行结束.....")

(3)第三种(继承):

import threading
import time
import _thread

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

    # 重写run方法, 实现多线程, 因为start方法执行时, 调用的是run方法;
    # run方法里面编写的内容就是你要执行的任务;
    def run(self):
        print("这是一个需要执行的任务%s。。。。。" %(self.jobName))
        print("当前线程的个数:", threading.active_count() )
        time.sleep(1)
        print("当前线程的信息:", threading.current_thread())
if __name__ == '__main__':
    t1 = MyThread("name1")
    t2 = MyThread("name2")
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("程序执行结束.....")

3.使用多线程案例与未使用对比

(1)未使用多线程案例

# 1. 简单的爬虫:
import time
from urllib.request import urlopen

def timeit(f):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        res = f(*args, **kwargs)
        end_time = time.time()
        print("%s函数运行时间:%.2f" % (f.__name__, end_time - start_time))
        return res

    return wrapper

def get_addr(ip):
    url = "http://ip-api.com/json/%s" % (ip)
    urlObj = urlopen(url)
    
    # 服务端返回的页面信息, 此处为字符串类型
    pageContent = urlObj.read().decode('utf-8')

    # 2. 处理Json数据
    import json
    # 解码: 将json数据格式解码为python可以识别的对象;
    dict_data = json.loads(pageContent)

    print("""
                        %s
    所在城市: %s
    所在国家: %s
    
    """ % (ip, dict_data['city'], dict_data['country']))

@timeit
def main():
    ips = ['12.13.14.%s' % (i + 1) for i in range(10)]
    for ip in ips:
        get_addr(ip)

if __name__ == '__main__':
    main()

main函数运行时间:4.15

(2)使用多线程案例

# 1. 简单的爬虫:
import threading
import time
from urllib.request import urlopen

def timeit(f):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        res = f(*args, **kwargs)
        end_time = time.time()
        print("%s函数运行时间:%.2f" % (f.__name__, end_time - start_time))
        return res
    return wrapper

def get_addr(ip):
    url = "http://ip-api.com/json/%s" % (ip)
    urlObj = urlopen(url)

    # 服务端返回的页面信息, 此处为字符串类型
    pageContent = urlObj.read().decode('utf-8')

    # 2. 处理Json数据
    import json
    # 解码: 将json数据格式解码为python可以识别的对象;
    dict_data = json.loads(pageContent)

    print("""
                        %s
    所在城市: %s
    所在国家: %s
    
    """ % (ip, dict_data['city'], dict_data['country']))

@timeit
def main():
    ips = ['12.13.14.%s' % (i + 1) for i in range(10)]
    threads = []
    for ip in ips:
        t = threading.Thread(target=get_addr, args=(ip, ))
        threads.append(t)
        t.start()

    [thread.join() for thread in threads]

if __name__ == '__main__':
    main()

main函数运行时间:1.95

结论:使用多线程的案例用时少于未使用的

疑问: python使用多线程, 一定运行速度快么? 为什么?

  • GIL(global interpreter lock)
  • python解释器中任意时刻都只有一个线程在执行;
  • GIL执行过程:
    • 1). 设置一个GIL;
    • 2). 切换线程去准备执行任务(Runnale就绪状态);
    • 3). 运行;
    • 4). 可能出现的状态:
      - 线程任务执行结束;
      - time.sleep()
      - 需要获取其他的信息才能继续执行(eg: 读取文件, 需要从网络下载html网页)
    • 5). 将线程设置为睡眠状态;
    • 5). 解GIL的锁;

多线程的应用场景: I/O密集型(input, output) — 爬虫
不建议使用多线程的场景: 计算密集型(cpu一直占用)

猜你喜欢

转载自blog.csdn.net/qq_43273590/article/details/86578193
今日推荐