概述
现实⽣活中有很多的场景中的事情是同时进⾏的,⽐如开⻋的时候 ⼿和脚共同来驾驶汽⻋,再⽐如唱歌跳舞也是同时进⾏的,这是现实⽣活中的多任务。
什么叫“多任务”呢?
就是操作系统可以同时运⾏多个任务。打个 ⽐⽅,你⼀边在⽤浏览器上⽹,⼀边在听MP3,⼀边在⽤Word赶作业,这就是多任务,⾄少同时有3个任务正在运⾏。还有很多任务悄悄地在后台同时运⾏着,只是桌⾯上没有显示⽽已。
单核CPU如何实现“多任务”呢?
操作系统轮流让各个任务交替执⾏,每个任务执⾏0.01秒,这样反复执⾏下去。 表⾯上看,每个任务交替执⾏,但CPU的执⾏速度实在是太快了,感觉就像所有任务都在同时执⾏⼀样。
多核CPU如何实现“多任务”呢?
真正的并⾏执⾏多任务只能在多核CPU上实现,但是,由于任务数量远远多 于CPU的核⼼数量,所以,操作系统也会⾃动把很多任务轮流调度到每个核⼼上执⾏。
多进程编程
进程 VS 程序
- 编写完毕的代码,在没有运⾏的时候,称之为程序
- 正在运⾏着的代码,就成为进程
注意: 进程,除了包含代码以外,还有需要运⾏的环境等,所以和程序是有区别的
进程的五状态模型
创建⼦进程
Python的os模块封装了常⻅的系统调⽤,其中就包括fork,可以在Python程 序中轻松创建⼦进程:
# 代码
"""
多进程中,每个进程中所有数据(包括全局变量)都各有拥有⼀份,互 不影响
"""
import os
import time
# 定义一个全局变量money
money = 100
print("当前进程的pid:", os.getpid())
print("当前进程的父进程pid:", os.getppid())
# time.sleep(115)
p = os.fork()
# 子进程返回的是0
if p == 0:
money = 200
print("子进程返回的信息, money=%d" % (money))
# 父进程返回的是子进程的pid
else:
print("创建子进程%s, 父进程是%d" % (p, os.getppid()))
print(money)
# 运行结果
当前进程的pid: 4073
当前进程的父进程pid: 3858
创建子进程4076, 父进程是3858
100
子进程返回的信息, money=200
多进程修改全局变量
多进程中,每个进程中所有数据(包括全局变量)都各有拥有⼀份,互 不影响
Windows没有fork调⽤,由于Python是跨平台的, multiprocessing模块就是跨平台版本的多进程模块。multiprocessing模块提供了⼀个Process类来代表⼀个进程对象。
Process([group [, target [, name [, args [, kwargs]]]]])
- target:表示这个进程实例所调⽤对象;
- args:表示调⽤对象的位置参数元组;
- kwargs:表示调⽤对象的关键字参数字典;
- name:为当前进程实例的别名;
- group:⼤多数情况下⽤不到;
Process类常⽤⽅法:
- is_alive(): 判断进程实例是否还在执⾏;
- join([timeout]): 是否等待进程实例执⾏结束,或等待多少秒;
- start(): 启动进程实例(创建⼦进程);
- run(): 如果没有给定target参数,对这个对象调⽤start()⽅法,就将执 ⾏对象中的run()⽅法;
- terminate(): 不管任务是否完成,⽴即终⽌;
Process类常⽤属性:
- name:当前进程实例别名,默认Process-N,N为从1开始计数;
- pid:当前进程实例的PID值;
多进程编程方法1: 实例化对象
# 代码
"""
Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调⽤对象;
args:表示调⽤对象的位置参数元组;
kwargs:表示调⽤对象的关键字参数字典;
name:为当前进程实例的别名;
group:⼤多数情况下⽤不到;
Process类常⽤⽅法:
is_alive(): 判断进程实例是否还在执⾏;
join([timeout]): 是否等待进程实例执⾏结束,或等待多少秒;
start(): 启动进程实例(创建⼦进程);
run(): 如果没有给定target参数,对这个对象调⽤start()⽅法时,
就将执 ⾏对象中的run()⽅法;
terminate(): 不管任务是否完成,⽴即终⽌;
"""
from multiprocessing import Process
import time
def task1():
print("正在听音乐")
time.sleep(1)
def task2():
print("正在编程......")
time.sleep(0.5)
def no_multi():
task1()
task2()
def use_multi():
p1 = Process(target=task1)
p2 = Process(target=task2)
p1.start()
p2.start()
p1.join()
p2.join()
# p.join() 阻塞当前进程, 当p1.start()之后, p1就提示主进程, 需要等待p1进程执行结束才能向下执行, 那么主进程就乖乖等着, 自然不会执行p2.start()
# [process.join() for process in processes]
if __name__ == '__main__':
# 主进程
start_time1 = time.time()
# no_multi()
use_multi()
end_time1 = time.time()
start_time2 = time.time()
no_multi()
#use_multi()
end_time2 = time.time()
print('多进程:', end_time1 - start_time1)
print('no多进程:', end_time2 - start_time2)
# 运行结果
正在听音乐
正在编程......
正在听音乐
正在编程......
多进程: 1.004859209060669
no多进程: 1.5017831325531006
多进程编程方法2: 创建子类
为什么需要进程池Pool?
- 当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
- Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。
# 代码
def is_prime(num):
"""判断素数"""
if num == 1:
return False
for i in range(2, num):
if num % i == 0:
return False
else:
return True
def task(num):
if is_prime(num):
print("%d是素数" % (num))
from multiprocessing import Process
# 判断1000-1200之间所有的素数
def use_mutli():
ps = []
# 不要开启太多进程, 创建子进程会耗费时间和空间(内存);
for num in range(1, 1000):
# 实例化子进程对象
p = Process(target=task, args=(num,))
# 开启子进程
p.start()
# 存储所有的子进程对象
ps.append(p)
# 阻塞子进程, 等待所有的子进程执行结束, 再执行主进程;
[p.join() for p in ps]
# 判断1000-1200之间所有的素数
def no_mutli():
for num in range(1, 100000):
task(num)
def use_pool():
"""使用进程池"""
from multiprocessing import Pool
from multiprocessing import cpu_count # 4个
p = Pool(cpu_count())
p.map(task, list(range(1, 100000)))
p.close() # 关闭进程池
p.join() # 阻塞, 等待所有的子进程执行结束, 再执行主进程;
if __name__ == '__main__':
import time
start_time = time.time()
# 数据量大小 # 1000-1200 # 1-10000 # 1-100000
#no_mutli() # 0.0022416114807128906 # 0.416304349899292 # 32.093048334121704
use_mutli() # 0.3098759651184082
#use_pool() # 0.11305379867553711 # 0.31943798065185547 # 16.613759994506836
end_time = time.time()
print(end_time - start_time)
进程间通信
WHY?
How?
消息队列
可以使⽤multiprocessing模块的Queue实现多进程之间的数据传递,Queue 本身是⼀个消息列队程序。
Queue.qsize():
- 返回当前队列包含的消息数量;
- Queue.empty(): 如果队列为空,返回True,反之False ;
- Queue.full(): 如果队列满了,返回True,反之False;
多线程编程
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
每个进程至少有一个线程,即进程本身。进程可以启动多个线程。操作系统像并行“进程”一样执行这些线程。
线程和进程各自有什么区别和优劣呢?
- 进程是资源分配的最小单位,线程是程序执行的最小单位。
- 进程有自己的独立地址空间。线程是共享进程中的数据的,使用相同的地址空间.
- 进程之间的通信需要以通信的方式(IPC)进行。线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,难点:处理好同步与互斥。
线程分类
有两种不同的线程:
- 内核线程
- 用户空间线程或用户线程 ,内核线程是操作系统的一部分,而内核中没有实现用户空间线程。
多线程编程
方法一
python的thread模块是⽐较底层的模块,python的threading 模块是对thread做了⼀些包装的,可以更加⽅便的被使⽤。
方法一分析
- 多线程程序的执⾏顺序是不确定的。
- 当执⾏到sleep语句时,线程将被阻塞(Blocked),到sleep结束后,线程进⼊就绪(Runnable)状态,等待调度。⽽线程调度将⾃⾏选择⼀个线程执⾏。
- 代码中只能保证每个线程都运⾏完整个run函数,但是线程的启动顺序、 run函数中每次循环的执⾏顺序都不能确定。
线程的⼏种状态
项目案例: IP地址归属地批量查询任务
# 代码
import requests
import json
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from threading import Thread
def task(ip):
"""获取指定IP的所在城市和国家并存储到数据库中"""
# 获取网址的返回内容
url = 'http://ip-api.com/json/%s' % (ip)
try:
response = requests.get(url)
except Exception as e:
print("网页获取错误:", e)
else:
# 默认返回的是字符串
"""
{"as":"AS174 Cogent Communications","city":"Beijing","country":"China","countryCode":"CN","isp":"China Unicom Shandong Province network","lat":39.9042,"lon":116.407,"org":"NanJing XinFeng Information Technologies, Inc.","query":"114.114.114.114","region":"BJ","regionName":"Beijing","status":"success","timezone":"Asia/Shanghai","zip":""}
"""
contentPage = response.text
# 将页面的json字符串转换成便于处理的字典;
data_dict = json.loads(contentPage)
# 获取对应的城市和国家
city = data_dict.get('city', 'null') # None
country = data_dict.get('country', 'null')
print(ip, city, country)
# 存储到数据库表中ips
ipObj = IP(ip=ip, city=city, country=country)
session.add(ipObj)
session.commit()
if __name__ == '__main__':
engine = create_engine("mysql+pymysql://root:123@172.25.4.10/student",
encoding='utf8',
# echo=True
)
# 创建缓存对象
Session = sessionmaker(bind=engine)
session = Session()
# 声明基类
Base = declarative_base()
class IP(Base):
__tablename__ = 'ips'
id = Column(Integer, primary_key=True, autoincrement=True)
ip = Column(String(20), nullable=False)
city = Column(String(30))
country = Column(String(30))
def __repr__(self):
return self.ip
# 创建数据表
Base.metadata.create_all(engine)
# 1.1.1.1 -- 1.1.1.10
threads = []
for item in range(10):
ip = '1.1.1.' + str(item + 1) # 1.1.1.1 -1.1.1.10
# task(ip)
# 多线程执行任务
thread = Thread(target=task, args=(ip,))
# 启动线程并执行任务
thread.start()
# 存储创建的所有线程对象;
threads.append(thread)
[thread.join() for thread in threads]
print("任务执行结束.........")
print(session.query(IP).all())
# 运行结果
网页获取错误:网页获取错误: HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.1 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b202dba58>: Failed to establish a new connection: [Errno -2] Name or service not known'))
HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.2 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b202dbdd8>: Failed to establish a new connection: [Errno -2] Name or service not known'))网页获取错误: HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.4 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b202f8400>: Failed to establish a new connection: [Errno -2] Name or service not known'))
网页获取错误:网页获取错误: HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.3 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b202f8128>: Failed to establish a new connection: [Errno -2] Name or service not known'))
网页获取错误: HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.7 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b22b74e10>: Failed to establish a new connection: [Errno -2] Name or service not known'))
网页获取错误: HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.6 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b22b26ba8>: Failed to establish a new connection: [Errno -2] Name or service not known'))
网页获取错误:
HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.8 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b22b43e10>: Failed to establish a new connection: [Errno -2] Name or service not known'))
HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.5 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b202dbac8>: Failed to establish a new connection: [Errno -2] Name or service not known'))
网页获取错误: HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.10 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b22b43518>: Failed to establish a new connection: [Errno -2] Name or service not known'))
网页获取错误: HTTPConnectionPool(host='ip-api.com', port=80): Max retries exceeded with url: /json/1.1.1.9 (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f7b22b431d0>: Failed to establish a new connection: [Errno -2] Name or service not known'))
任务执行结束.........
[1.1.1.5, 1.1.1.7, 1.1.1.2, 1.1.1.4, 1.1.1.3, 1.1.1.10, 1.1.1.1, 1.1.1.6, 1.1.1.8, 1.1.1.9, 1.1.1.10, 1.1.1.4, 1.1.1.1, 1.1.1.2, 1.1.1.6, 1.1.1.3, 1.1.1.8, 1.1.1.5, 1.1.1.7]
在数据库中查看获取的IP地址归属地
项目案例: 基于多线程的批量主机存活探测
项目描述: 如果要在本地网络中确定哪些地址处于活动状态或哪些计算机处于活动状态,则可以使用此脚本。我们将依次ping地址, 每次都要等几秒钟才能返回值。这可以在Python中编程,在IP地址的地址范围内有一个for循环和一个os.popen(“ping -q -c2”+ ip)。
项目瓶颈: 没有线程的解决方案效率非常低,因为脚本必须等待每次ping。
# 代码
"""
创建子类
"""
from threading import Thread
class GetHostAliveThread(Thread):
"""
创建子线程, 执行的任务:判断指定的IP是否存活
"""
def __init__(self, ip):
super(GetHostAliveThread, self).__init__()
self.ip = ip
def run(self):
# # 重写run方法: 判断指定的IP是否存活
# """
# >>> # os.system() 返回值如果为0, 代表命令正确执行,没有报错; 如果不为0, 执行报错;
# ...
# >>> os.system('ping -c1 -w1 172.25.254.49 &> /dev/null')
# 0
# >>> os.system('ping -c1 -w1 172.25.254.1 &> /dev/null')
# 256
# """
import os
# 需要执行的shell命令
cmd = 'ping -c1 -w1 %s &> /dev/null' %(self.ip)
result = os.system(cmd)
# 返回值如果为0, 代表命令正确执行,没有报错; 如果不为0, 执行报错;
if result != 0:
print("%s主机没有ping通" %(self.ip))
if __name__ == '__main__':
print("打印172.25.254.0网段没有使用的IP地址".center(50, '*'))
for i in range(1, 255):
ip = '172.25.254.' + str(i)
thread = GetHostAliveThread(ip)
thread.start()
# 运行结果
************打印172.25.254.0网段没有使用的IP地址*************
172.25.254.61主机没有ping通172.25.254.62主机没有ping通172.25.254.110主机没有ping通
172.25.254.90主机没有ping通
172.25.254.128主机没有ping通
172.25.254.86主机没有ping通
172.25.254.69主机没有ping通
172.25.254.120主机没有ping通
172.25.254.82主机没有ping通
172.25.254.15主机没有ping通
172.25.254.87主机没有ping通
172.25.254.67主机没有ping通
172.25.254.21主机没有ping通
172.25.254.92主机没有ping通
172.25.254.34主机没有ping通
172.25.254.9主机没有ping通
172.25.254.113主机没有ping通
172.25.254.118主机没有ping通
172.25.254.117主机没有ping通
172.25.254.112主机没有ping通
172.25.254.76主机没有ping通
172.25.254.95主机没有ping通
172.25.254.43主机没有ping通
172.25.254.65主机没有ping通
172.25.254.104主机没有ping通
172.25.254.31主机没有ping通
172.25.254.71主机没有ping通
172.25.254.106主机没有ping通
172.25.254.59主机没有ping通
172.25.254.46主机没有ping通
172.25.254.119主机没有ping通
172.25.254.24主机没有ping通
172.25.254.35主机没有ping通
172.25.254.45主机没有ping通
172.25.254.33主机没有ping通
172.25.254.50主机没有ping通
172.25.254.58主机没有ping通
172.25.254.51主机没有ping通
172.25.254.79主机没有ping通172.25.254.6主机没有ping通
172.25.254.44主机没有ping通
172.25.254.56主机没有ping通
172.25.254.2主机没有ping通
172.25.254.114主机没有ping通
172.25.254.17主机没有ping通
172.25.254.77主机没有ping通
172.25.254.98主机没有ping通
172.25.254.53主机没有ping通
172.25.254.83主机没有ping通
172.25.254.99主机没有ping通
172.25.254.72主机没有ping通
172.25.254.68主机没有ping通
172.25.254.18主机没有ping通
172.25.254.116主机没有ping通
172.25.254.19主机没有ping通
172.25.254.27主机没有ping通
172.25.254.13主机没有ping通
172.25.254.107主机没有ping通
172.25.254.109主机没有ping通
172.25.254.75主机没有ping通
172.25.254.10主机没有ping通
172.25.254.1主机没有ping通
172.25.254.16主机没有ping通
172.25.254.103主机没有ping通
172.25.254.91主机没有ping通
172.25.254.101主机没有ping通
172.25.254.89主机没有ping通172.25.254.85主机没有ping通
172.25.254.41主机没有ping通
172.25.254.60主机没有ping通
172.25.254.93主机没有ping通
172.25.254.74主机没有ping通
172.25.254.78主机没有ping通
172.25.254.81主机没有ping通
172.25.254.54主机没有ping通
172.25.254.25主机没有ping通
172.25.254.64主机没有ping通
172.25.254.105主机没有ping通
172.25.254.55主机没有ping通
172.25.254.80主机没有ping通
172.25.254.66主机没有ping通
172.25.254.14主机没有ping通
172.25.254.160主机没有ping通
172.25.254.8主机没有ping通
172.25.254.57主机没有ping通
172.25.254.84主机没有ping通
172.25.254.97主机没有ping通
172.25.254.115主机没有ping通
172.25.254.96主机没有ping通
172.25.254.40主机没有ping通
172.25.254.102主机没有ping通
172.25.254.32主机没有ping通
172.25.254.111主机没有ping通
172.25.254.5主机没有ping通
172.25.254.73主机没有ping通
172.25.254.108主机没有ping通
172.25.254.94主机没有ping通
172.25.254.7主机没有ping通
172.25.254.37主机没有ping通
172.25.254.12主机没有ping通
172.25.254.166主机没有ping通
172.25.254.20主机没有ping通
172.25.254.11主机没有ping通
172.25.254.100主机没有ping通
172.25.254.38主机没有ping通
172.25.254.52主机没有ping通
172.25.254.36主机没有ping通
172.25.254.203主机没有ping通
172.25.254.42主机没有ping通
172.25.254.26主机没有ping通
172.25.254.30主机没有ping通
172.25.254.248主机没有ping通172.25.254.143主机没有ping通
172.25.254.226主机没有ping通
172.25.254.179主机没有ping通
172.25.254.219主机没有ping通
172.25.254.237主机没有ping通172.25.254.213主机没有ping通
172.25.254.250主机没有ping通
172.25.254.209主机没有ping通
172.25.254.247主机没有ping通
172.25.254.224主机没有ping通
172.25.254.230主机没有ping通
172.25.254.241主机没有ping通
172.25.254.211主机没有ping通
172.25.254.239主机没有ping通
172.25.254.170主机没有ping通
172.25.254.244主机没有ping通172.25.254.125主机没有ping通
172.25.254.131主机没有ping通172.25.254.181主机没有ping通172.25.254.168主机没有ping通
172.25.254.121主机没有ping通
172.25.254.148主机没有ping通
172.25.254.253主机没有ping通
172.25.254.218主机没有ping通172.25.254.175主机没有ping通172.25.254.154主机没有ping通
172.25.254.126主机没有ping通
172.25.254.202主机没有ping通
172.25.254.185主机没有ping通
172.25.254.223主机没有ping通
172.25.254.198主机没有ping通
172.25.254.221主机没有ping通172.25.254.173主机没有ping通172.25.254.238主机没有ping通
172.25.254.228主机没有ping通
172.25.254.142主机没有ping通
172.25.254.249主机没有ping通
172.25.254.130主机没有ping通
172.25.254.147主机没有ping通
172.25.254.124主机没有ping通
172.25.254.229主机没有ping通
172.25.254.159主机没有ping通
172.25.254.171主机没有ping通
172.25.254.246主机没有ping通172.25.254.146主机没有ping通
172.25.254.163主机没有ping通
172.25.254.155主机没有ping通
172.25.254.176主机没有ping通
172.25.254.199主机没有ping通
172.25.254.167主机没有ping通
172.25.254.162主机没有ping通
172.25.254.200主机没有ping通172.25.254.206主机没有ping通
172.25.254.227主机没有ping通
172.25.254.144主机没有ping通
172.25.254.214主机没有ping通
172.25.254.184主机没有ping通
172.25.254.174主机没有ping通
172.25.254.252主机没有ping通
172.25.254.157主机没有ping通
172.25.254.222主机没有ping通
172.25.254.234主机没有ping通
172.25.254.138主机没有ping通
172.25.254.141主机没有ping通
172.25.254.161主机没有ping通
172.25.254.153主机没有ping通
172.25.254.178主机没有ping通172.25.254.210主机没有ping通
172.25.254.191主机没有ping通
172.25.254.242主机没有ping通
172.25.254.195主机没有ping通
172.25.254.190主机没有ping通
172.25.254.177主机没有ping通
172.25.254.133主机没有ping通
172.25.254.216主机没有ping通
172.25.254.149主机没有ping通172.25.254.207主机没有ping通172.25.254.136主机没有ping通
172.25.254.187主机没有ping通
172.25.254.194主机没有ping通
172.25.254.201主机没有ping通
172.25.254.145主机没有ping通172.25.254.196主机没有ping通
172.25.254.140主机没有ping通
172.25.254.151主机没有ping通
172.25.254.156主机没有ping通
172.25.254.182主机没有ping通
172.25.254.172主机没有ping通
172.25.254.231主机没有ping通
172.25.254.183主机没有ping通
172.25.254.189主机没有ping通
172.25.254.212主机没有ping通
172.25.254.204主机没有ping通
172.25.254.158主机没有ping通
172.25.254.243主机没有ping通
172.25.254.135主机没有ping通
172.25.254.217主机没有ping通172.25.254.137主机没有ping通
172.25.254.205主机没有ping通
172.25.254.132主机没有ping通
172.25.254.169主机没有ping通
172.25.254.215主机没有ping通
172.25.254.165主机没有ping通
172.25.254.129主机没有ping通
172.25.254.186主机没有ping通
172.25.254.134主机没有ping通
172.25.254.235主机没有ping通
172.25.254.122主机没有ping通
172.25.254.240主机没有ping通
172.25.254.236主机没有ping通
172.25.254.245主机没有ping通
172.25.254.164主机没有ping通
172.25.254.254主机没有ping通
172.25.254.233主机没有ping通172.25.254.152主机没有ping通
172.25.254.208主机没有ping通
172.25.254.127主机没有ping通
172.25.254.225主机没有ping通
172.25.254.220主机没有ping通
172.25.254.150主机没有ping通
172.25.254.232主机没有ping通172.25.254.197主机没有ping通
172.25.254.193主机没有ping通
172.25.254.180主机没有ping通
172.25.254.192主机没有ping通
172.25.254.188主机没有ping通
172.25.254.63主机没有ping通
共享全局变量
优点: 在⼀个进程内的所有线程共享全局变量,能够在不使⽤其他⽅式的前提下完成多线程之间的数据共享(这点要⽐多进程要好)
缺点: 线程是对全局变量随意遂改可能造成多线程之间对全局变量 的混乱(即线程⾮安全)
共享全局变量:如何解决线程不安全问题?
GIL(global interpreter lock): python解释器中任意时刻都只有一个线程在执行;
Python代码的执行由Python 虚拟机(也叫解释器主循环,CPython版本)来控制,Python 在设计之初就考虑到要在解释器的主循环中,同时只有一个线程在执行,即在任意时刻,只有一个线程在解释器中运行。对Python 虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
线程同步
线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作.
同步就是协同步调,按预定的先后次序进⾏运⾏。如:你说完,我再说。 "同"字从字⾯上容易理解为⼀起动作 其实不是, "同"字应是指协同、协助、互相配合。
线程锁
多线程可以同时运行多个任务,但是当多个线程同时访问共享数据时,可能导致数据不同步,甚至错误!
so,不使用线程锁, 可能导致错误
如何实现线程锁
#锁的使用
#创建锁
lock = threading.Lock()
#操作变量之前进行加锁
lock.acquire([timeout])
#操作变量之后进行解锁
lock.release()
死锁
在线程间共享多个资源的时候,如果两个线程分别占有⼀部分资源并且同时等待对⽅的资源,就会造成死锁。
协程
协程,又称微线程,纤程。英文名Coroutine。
协程看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。
协程优势
- 执行效率极高,因为子程序切换(函数)不是线程切换,由程序自身控制
- 没有切换线程的开销。所以与多线程相比,线程的数量越多,协程性能的优势越明显
- 不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在控制共享资源时也不需要加锁,因此执行效率高很多
最后
以上就是丰富黑裤为你收集整理的多任务编程的全部内容,希望文章能够帮你解决多任务编程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复