操作系统/应用程序/操作系统中的并发/线程与进程(Python中有GIL锁)

一.操作系统/应用程序

1.硬件:

硬件是计算机硬件的简称,是指计算机系统中由电子,机械和光电元件等组成的各种物理装置的总称。这些物理装置按系统结构的要求构成一个有机整体为计算机软件运行提供物质基础。简言之,硬件的功能是输入并存储程序和数据,以及执行程序把数据加工成可以利用的形式。从外观上来看,微机由主机箱和外部设备组成。主机箱内主要包括CPU、内存、主板、硬盘驱动器、光盘驱动器、各种扩展卡、连接线、电源等;外部设备包括鼠标、键盘等。

2.操作系统:

操作系统(简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。操作系统是用户和计算机的接口,同时也是计算机硬件和其他软件的接口。操作系统的功能包括管理计算机的硬件、软件及数据资源,控制程序运行,改善人机界面,为其它应用软件提供支持,让计算机所有资源最大限度地发挥作用,提供各种形式的用户界面,使用户有一个好的工作环境,为其它软件的开发提供必要的服务和相应的接口等。实际上,用户是不用接触操作系统的,操作系统管理着计算机硬件资源,同时按照应用程序的资源请求,分配资源,如:划分CPU时间,内存空间的开辟,调用打印机等。

3.应用程序:

(1).应用程式是电脑软体的主要分类之一,是指为针对使用者的某种应用目的所撰写的软体。

(2).应用程式通常又被分为两部分:图形使用者介面(GUI)和引擎 (Engine)。它与应用软体的概念不同。应用软体指使用的目的分类,可以是单一程式或其他从属元件的集合,例如Microsoft Office、OpenOffice。应用程式指单一可执行档或单一程式,例如Word、Photoshop。日常中可不将两者仔细区分。一般视程式为软体的一个组成部分。

 二.操作系统中的并发与并行

1.并行:并行是指两者同时执行,比如有两条车道,在某一个时间点,两条车道上都有车在跑;(资源够用,比如三个线程,四核的CPU )

2.并发:并发是指资源有限的情况下,两者交替轮流使用资源,比如只有一条车道(单核CPU资源),那么就是A车先走,在某个时刻A车退出把道路让给B走,B走完继续给A ,交替使用,目的是提高效率。

3.区别:

  (1).并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。
  (2).并发是从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个session。

  注意:早期单核CPU时候,对于进程也是微观上串行(站在cpu角度看),宏观上并行(站在人的角度看就是同时有很多程序在执行)。

4.同步:所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。

5.异步:所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。

6.阻塞与非阻塞

  阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的

三.线程与进程

Python没有这玩意,Python中调用的是操作系统的线程与进程

1、线程的基本概念

(1).概念:

线程是进程中执行运算的最小单位,是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。

(2)好处:

  易于调度。

  提高并发性。通过线程可方便有效地实现并发性。进程可创建多个线程来执行同一程序的不同部分。

  开销少。创建线程比创建进程要快,所需开销很少

2、进程的基本状态及状态之间的关系

状态:运行、阻塞、挂起阻塞、就绪、挂起就绪

  状态之间的转换:

    (1)准备就绪的进程,被CPU调度执行,变成运行态;

    (2)运行中的进程,进行I/O请求或者不能得到所请求的资源,变成阻塞态;

    (3)运行中的进程,进程执行完毕(或时间片已到),变成就绪态;

    (4)将阻塞态的进程挂起,变成挂起阻塞态,当导致进程阻塞的I/O操作在用户重启进程前完成(称之为唤醒),挂起阻塞态变成挂起就绪态,当用户在I/O操作结束之前重启进程,挂起阻塞态变成阻塞态;

    (5)将就绪(或运行)中的进程挂起,变成挂起就绪态,当该进程恢复之后,挂起就绪态变成就绪态;

3、线程和进程的关系以及区别?

  进程和线程的关系:

    (1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。

    (2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。

    (3)处理机分给线程,即真正在处理机上运行的是线程

    (4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。线程是指进程内的一个执行单元,也是进程内的可调度实体.

  进程与线程的区别

    (1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

    (2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行

    (3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.

    (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。

print('666')
单线程,单进程的应用程序
import threading
print('666')

def func(arg):
    print(arg)
t = threading.Thread(target=func)
t.start()

print('end')
单进程,多线程的应用程序
 一个应用程序(软件),可以有多个进程(默认只有一个),一个进程中可以创建多个线程(默认一个)

4.线程的使用

(1).Threading模块:

  Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元

(2).更多方法:

  start     线程准备就绪,等待CPU调度

  setName      为线程设置名称

  getName      获取线程名称

  setDaemon   设置为后台线程或前台线程(默认)  守护进程:setDaemon=False

      如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程

      不论成功与否,均停止

      如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台

      线程也执行完成后,程序停止

  join      逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

  run     线程被cpu调度后自动执行线程对象的run方法

def func(arg):
    print(arg)

t = threading.Thread(target=func,args=(11,))
t.start()

print(123)

结果:
11
123
end
线程的基本使用 
import time
def func(arg):
    time.sleep(arg)
    print(arg)

t1 = threading.Thread(target=func,args=(3,))
t1.start()

t2 = threading.Thread(target=func,args=(9,))
t2.start()

print(123)

结果:
123
end
...等一会
3
9
主线程默认等子线程执行完毕
import time
def func(arg):
    time.sleep(2)
    print(arg)

t1 = threading.Thread(target=func,args=(3,))
t1.setDaemon(True)
t1.start()

t2 = threading.Thread(target=func,args=(9,))
t2.setDaemon(True)
t2.start()

print(123)

结果:
123
end
主线程不再等,主线程终止则所有子线程终止
import time
def func(arg):
    time.sleep(0.01)
    print(arg)

print('创建子线程t1')
t1 = threading.Thread(target=func,args=(3,))
t1.start()
# 无参数,让主线程在这里等着,等到子线程t1执行完毕,才可以继续往下走。
# 有参数,让主线程在这里最多等待n秒,无论是否执行完毕,会继续往下走。
t1.join(2)

print('创建子线程t2')
t2 = threading.Thread(target=func,args=(9,))
t2.start()
t2.join(2) # 让主线程在这里等着,等到子线程t2执行完毕,才可以继续往下走。

print(123)

结果:
123
创建子线程t1
3
创建子线程t2
9
123
end
开发者可以控制主线程等待子线程(最多等待时间)
# 先打印:11?123?
def func(arg):
    print(arg)

t1 = threading.Thread(target=func,args=(11,))
t1.start()
# start 是开始运行线程吗?不是
# start 告诉cpu,我已经准备就绪,你可以调度我了。
print(123)

结果:
123
11
123
end
线程本质
# 多线程方式:1 (常见)
def func(arg):
    print(arg)

t1 = threading.Thread(target=func,args=(11,))
t1.start()

结果:
123
11


# 多线程方式:2
class MyThread(threading.Thread):

    def run(self):
        print(11111,self._args,self._kwargs)

t1 = MyThread(args=(11,))
t1.start()

t2 = MyThread(args=(22,))
t2.start()

print('end')

结果:
123
11111 (11,) {}
11111 (22,) {}
end
面向对象版本的多线程

 5.Python多线的情况下:

  计算密集型操作:效率低.(GIL锁)

  IO操作:效率高

6.Python多进程的情况下:

  计算密集型操作:效率高(浪费资源). 不得已而为之

  IO操作:效率高(浪费资源)

7.以后写Python时:

  IO密集型用多线程:文件/输入输出/socket网络通信

  计算密集型用多线程

8.扩展

  JAVA多线程的情况下:

    计算密集型操作:效率高

    IO操作:效率高

  Python多进程的情况下:

    计算密集型操作:效率高(浪费资源)

    IO操作:效率高(浪费资源)

四.Python中线程和进程(GIL锁)

GIL锁:全局解释器锁,用于限制一个进程中同一时刻只有一个线程被CPU调用

扩展:默认GIL锁在执行100个CPU指令(过期时间)

import sys

v1 = sys.getcheckinterval()
print(v1)

结果:100
查看GIL切换指令

1.Python线程的编写

(1).计算密集型多线程无用

import threading
v1 = [11,22,33] # +1
v2 = [44,55,66] # 100


def func(data,plus):
    for i in range(len(data)):
        data[i] = data[i] + plus
    print(data)

t1 = threading.Thread(target=func,args=(v1,1))
t1.start()

t2 = threading.Thread(target=func,args=(v2,100))
t2.start()

结果:
[12, 23, 34]
[144, 155, 166]
View Code

 (2).IO操作,多线程有用

import threading
import requests
import uuid

url_list = [
    'https://www3.autoimg.cn/newsdfs/g28/M05/F9/98/120x90_0_autohomecar__ChsEnluQmUmARAhAAAFES6mpmTM281.jpg',
    'https://www2.autoimg.cn/newsdfs/g28/M09/FC/06/120x90_0_autohomecar__ChcCR1uQlD6AT4P3AAGRMJX7834274.jpg',
    'https://www2.autoimg.cn/newsdfs/g3/M00/C6/A9/120x90_0_autohomecar__ChsEkVuPsdqAQz3zAAEYvWuAspI061.jpg',
]

def task(url):
    ret = requests.get(url)
    file_name = str(uuid.uuid4()) + '.jpg'
    with open(file_name, mode='wb') as f:
        f.write(ret.content)

for url in url_list:

    t = threading.Thread(target=task,args=(url,))
    t.start()
View Code

 (3).多线程的问题

import time
import threading

lock = threading.RLock()

n = 10

def task(i):
    print('这段代码不加锁',i)

    lock.acquire() # 加锁,此区域的代码同一时刻只能有一个线程执行
    global n
    print('当前线程',i,'读取到的n值为:',n)
    n = i
    time.sleep(1)
    print('当前线程',i,'修改n值为:',n)
    lock.release() # 释放锁


for i in range(10):
    t = threading.Thread(target=task,args=(i,))
    t.start()

结果:
这段代码不加锁 0
当前线程 0 读取到的n值为: 10
这段代码不加锁 1
这段代码不加锁 2
这段代码不加锁 3
这段代码不加锁 4
这段代码不加锁 5
这段代码不加锁 6
这段代码不加锁 7
这段代码不加锁 8
这段代码不加锁 9
...每输出一项,等一秒
当前线程 0 修改n值为: 0
当前线程 1 读取到的n值为: 0
当前线程 1 修改n值为: 1
当前线程 2 读取到的n值为: 1
当前线程 2 修改n值为: 2
当前线程 3 读取到的n值为: 2
当前线程 3 修改n值为: 3
当前线程 4 读取到的n值为: 3
当前线程 4 修改n值为: 4
当前线程 5 读取到的n值为: 4
当前线程 5 修改n值为: 5
当前线程 6 读取到的n值为: 5
当前线程 6 修改n值为: 6
当前线程 7 读取到的n值为: 6
当前线程 7 修改n值为: 7
当前线程 8 读取到的n值为: 7
当前线程 8 修改n值为: 8
当前线程 9 读取到的n值为: 8
当前线程 9 修改n值为: 9
View Code
posted @ 2018-09-10 19:38  骑驴老神仙  阅读(299)  评论(0)    收藏  举报