怎么掌握云计算核心技术 Docker容器怎么回事

怎么掌握云计算核心技术?Docker容器怎么回事?Docker容器是一个开源的应用容器引擎,随着云计算的迅猛发展而被人们熟知。一个合格的云计算工程是一定要熟练掌握Docker容器技术,接下来小编就给大家梳理汇总Docker容器相关知识。

%title插图%num

Docker主要有如下几个概念:

引擎:创建和管理容器的工具,通过读取镜像来生成容器,并负责从仓库拉取镜像或提交镜像到仓库中;

镜像:类似于虚拟机镜像,一般由一个基本操作系统环境和多个应用程序打包而成,是创建容器的模板;

容器:可看作一个简易版的Linxu系统环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子;

仓库:集中存放镜像文件的场所,分为公共仓库和私有仓库,目前*大的公共仓库是官方提供的Docker Hub,此外国内的阿里云、腾讯云等也提供了公共仓库;

宿主机:运行引擎的操作系统所在服务器。

Docker镜像采用分层存储格式,每个镜像可依赖其他镜像进行构建,每一层的镜像可被多个镜像引用。这种分层结构能充分共享镜像层,能大大减少镜像仓库占用的空间,而对用户而言,他们所看到的容器,其实是Docker利用UnionFS(联合文件系统)把相关镜像层的目录“联合”到同一个挂载点呈现出来的一个整体。

什么是UnionFS?UnionFS可以把多个物理位置独立的目录(也叫分支)内容联合挂载到同一个目录下,UnionFS允许控制这些目录的读写权限,此外对于只读的文件和目录,它具有“Copy on Write(写实复制)”的特点,即如果对一个只读的文件进行修改,在修改前会先把文件复制一份到可写层(可能是磁盘里的一个目录),所有的修改操作其实都是对这个文件副本进行修改,原来的只读文件并不会变化。

UnionFS有很多种,其中Docker中常用的是AUFS,这是UnionFS的升级版,除此之外还有DeviceMapper、Overlay2、ZFS和 VFS等。Docker镜像的每一层默认存放在/var/lib/docker/aufs/diff目录中,当用户启动一个容器时,Docker引擎首先在/var/lib/docker/aufs/diff中新建一个可读写层目录,然后使用UnionFS把该可读写层目录和指定镜像的各层目录联合挂载到/var/lib/docker/aufs/mnt里的一个目录中(其中指定镜像的各层目录都以只读方式挂载),通过LXC等技术进行环境隔离和资源控制,使容器里的应用仅依赖mnt目录中对应的挂载目录和文件运行起来。

利用UnionFS写实复制的特点,在启动一个容器时, Docker引擎实际上只是增加了一个可写层和构造了一个Linux容器,这两者都几乎不消耗系统资源,因此Docker容器能够做到秒级启动,一台服务器上能够启动上千个Docker容器,而传统虚拟机在一台服务器上启动几十个就已经非常吃力了,而且虚拟机启动很慢,这是Docker相比于传统虚拟机的两个巨大的优势。

Docker镜像制作方法

1)通过正在运行的容器生成新镜像。当一个容器在运行时,在里面所有的修改都会体现在容器的可写层,Docker提供了commit命令,可以把正在运行的容器,叠加上可写层的修改内容,生成一个新镜像。

2)通过Dockerfile文件来生成新镜像。Dockerfile是一个定义了镜像创建步骤的文件,Docker引擎通过build命令读取Dockerfile,按定义的步骤来一步步构造镜像。在研发和实施环境中,通过Dockerfile 创建容器是主流做法。

如果你想了解更多Docker容器技术,想快速加入云计算开发行列,你可以选择专业学习一下,让自己快速系统的掌握企业所需的云计算核心技术!

云计算开源工具有哪些 如何快速加入高薪行列

云计算开源工具有哪些?如何快速加入高薪行列?随着互联网的高速发展以及国家政策扶持,我国云计算行业发展迅猛,云计算人才也成为稀缺高薪人才。为了能够快速入行,很多人会选择专业学习一下,这已经成为大多数人的选择。

众所周知,云计算和开源是相爱相生的关系,借助开源社区的力量,云计算技术迅速占领市场,不过2020年常用的云计算开源工具有哪些呢?接下来就给大家介绍一下。

%title插图%num

1、Kubernetes

过去两年Kuberentes已成为火爆的开源项目之一,相信在未来Kuberentes的势头会更劲,其拥有大量的扩展工具,其优势在于:

1)通过基于角色的访问控制可以更好地支持企业部署;

2)将Kuberentes从单一用户操作系统转移到Unix;

3)支持在Kubernetes管理的容器和容器中运行有状态应用。

除了Kuberentes容器调度器外,CNCF(云原生基金会)还提供了一套广泛的兼容工具,用于操作和交付现代分布式系统,这些组合创建的功能可以扩展到成千上万个自修复的多租户节点上,同时还可以实现操作上的差异。

2、Fluentd

Fluentd是一个免费,而且完全开源的日志管理工具,简化了日志的收集、处理、和存储,可以不需要在维护编写特殊的日志处理脚本。Fluentd的性能已经在各领域得到了证明:目前*大的用户从5000+服务器收集日志,每天5TB的数据量,在高峰时间处理50000条信息每秒。

3、Prometheus

Prometheus(简称Prom)前身是SoundCloud的告警工具包,现已演化成一个独立的开源监控系统。它是一种度量标准的监控系统,旨在为监视服务提供云本地的方法。主要特性:1)多维度数据模型;2)时间序列数据通过metric名和键值对来区分,所有的metrics都可以设置任意的多维标签;3)数据模型随意,不需要刻意设置为以点分隔的字符串等。

4、Linkerd

Linkerd是一款开源网络代理,旨在作为服务网格进行部署:专用层,用于在应用程序内管理,控制和监视服务到服务的通信。通过为服务提供统一,统一的仪器和控制层,Linkerd免费服务所有者选择*适合其服务的语言。通过将通信机制与应用程序代码分离,Linkerd允许在不改变应用程序本身的情况下查看和控制这些机制。

5、CoreDNS

CoreDNS的前身是SkyDNS,它的主要目的是构建一个快速灵活的DNS服务器,让用户可以通过不同方式访问和使用DNS内的数据。它被设计为Caddy网络服务的一个服务器插件。CoreDNS的每个特性都可以被实现为可插拔的中间件,如日志、基于文件的DNS以及多种后端技术,进而可以拼接多个插件来创建定制化的管道。CoreDNS已经得到扩展,可以直接被Kubernetes访问服务数据,并以KubeDNS的形式提供给用户使用。

当然,除了以上工具,2020年比较常用的云计算开源工具还包括Containerd、gRPC、OpenTracing等。熟练掌握各种开源工具会让你在求职时更具优势,而想要快速加入到云计算这一高薪行列,参加专业学习是一个不错的选择。

云数据库六大优势是什么 如何学好云计算技能

云数据库六大优势是什么?如何学好云计算技能?数据库是前端还是后台开发人员都需要了解和掌握的工具,传统的数据库工程师需要掌握基础理论知识、数据库基础知识、数据库运维知识以及数据库性能调优技能。不过随着云时代的到来,云数据库的应用及大规模普及,给数据库工程师的日常工作带来了很大的积*影响,下面就给大家详细介绍一下云数据库的六大优势:

%title插图%num

1、免部署。云数据库种类丰富,关系型数据库如MySQL、PostgreSQL、SQL Server,非关系型数据库如MongoDB、Redis、Memcache,兼容和支持各种版本。通过简单的购买操作,分钟级甚至秒级交付,云数据库一键部署。

2、高性能。云数据库软硬件深度调优,具有理想的性能表现。同时,底层硬件较快引入*新高性能硬件,多种性能加持下,DBA可聚焦在应用层优化。

3、高可靠性。云数据库能够自动探测,及时容灾,保证数据库服务不中断。对于数据库工程师来说,也不需要再额外部署高可用架构。

4、强大的灵活性和扩展性。云数据库弹性扩展的能力,至少是支持垂直扩展(scale-up),通常也支持水平扩展(scale-out)。灵活性则是第三维度的扩展,它可以支持一主多从,读写分离。数据库工程师能够在短期内聚焦业务,暂时不会有扩展性的烦恼。

5、自带运维能力。云数据库通常支持自动备份和手动备份两种模式,提供一键回档的功能找回数据。并提供详细的监控数据,也可配置异常自动告警。可以说,数据库工程师对云数据库基本没有运维工作。

6、安全可靠。云数据库在数据存储、网络链路访问、鉴权认证、多租户隔离方面做了多重保障,以确保数据安全,除此之外,它可以支持数据库审计,后端自动漏洞扫描,定期安全加固等。

使用云数据库后,数据库工程师可以有更多时间关注其他技能的锻炼和培养,提升自己的综合竞争力。如果你想了解更多云计算技术,可以选择专业学习一下。

Python爬虫Scrapy轮子工具

Python爬虫Scrapy轮子工具

Scrapy
万字长文,建议使用目录点击查阅,有助于高效开发。建议点赞收藏

文章目录
Scrapy
概念
模块作用
开发步骤
爬虫文件 spiders.py
代码流程
提取数据
scrapy.Request发送post请求
发送post请求
response响应
Cookie
参数解释
meta参数的使用
管道 piplines.py
pipeline中常用的方法:
开启管道
多个管道的开启作用
MongoDB 持久化
Json 持久化
MySql 持久化
Csv持久化
中间件 middleware.py
中间件的分类
Scrapy中间的作用(预处理Request和Response对象)
Downloader Middlewares默认的方法:
fake_useragent
ip_proxy
方法一【免费代理】:
方法二【收费代理】:
Scrapy-redis
Scrapy-bloomfilter布隆过滤器
设置 settings.py
常用变量
启动运行
方法一【运行单个爬虫文件】:
方法二【 串行 运行完*个才会运行下一个】:
方法三【在进程里面跑多个爬虫】:
概念
scrapy框架的运行流程以及数据传递过程:

爬虫中起始的url构造成request对象–>爬虫中间件–>引擎–>调度器
调度器把request–>引擎–>下载中间件—>下载器
下载器发送请求,获取response响应—->下载中间件—->引擎—>爬虫中间件—>爬虫
爬虫提取url地址,组装成request对象—->爬虫中间件—>引擎—>调度器,重复步骤2
爬虫提取数据—>引擎—>管道处理和保存数据
模块作用
引擎(engine):负责数据和信号在不腰痛模块间的传递
调度器(scheduler):实现一个队列,存放引擎发过来的request请求对象
下载器(downloader):发送引擎发过来的request请求,获取响应,并将响应交给引擎
爬虫(spider):处理引擎发过来的response,提取数据,提取url,并交给引擎
管道(pipeline):处理引擎传递过来的数据,比如存储
下载中间件(downloader middleware):可以自定义的下载扩展,比如设置代理ip
爬虫中间件(spider middleware):可以自定义request请求和进行response过滤,与下载中间件作用重复

开发步骤
创建项目:

scrapy startproject mySpider
scrapy startproject <项目名字>

生成一个爬虫【在项目目录下执行】:

scrapy genspider lianjia lianjia.com
scrapy genspider <爬虫名字> <允许爬取的域名>

爬虫名字: 作为爬虫运行时的参数

允许爬取的域名: 为对于爬虫设置的爬取范围,设置之后用于过滤要爬取的url,如果爬取的url与允许的域不通则被过滤掉。

提取数据:

修改start_urls
检查修改allowed_domains
编写解析方法
根据网站结构在spider中实现数据采集相关内容

保存数据:

在pipelines.py文件中定义对数据处理的管道

在settings.py文件中注册启用管道

启动项目

爬虫文件 spiders.py
代码流程
完善并使用Item数据类:
在items.py中完善要爬取的字段
在爬虫文件中先导入Item
实力化Item对象后,像字典一样直接使用
构造Request对象,并发送请求:
导入scrapy.Request类
在解析函数中提取url
yield scrapy.Request(url, callback=self.parse_detail, meta={})
利用meta参数在不同的解析函数中传递数据:
通过前一个解析函数 yield scrapy.Request(url, callback=self.xxx, meta={}) 来传递meta
在self.xxx函数中 response.meta.get(‘key’, ‘’) 或 response.meta[‘key’] 的方式取出传递的数据
提取数据
解析并获取scrapy爬虫中的数据:
1. response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
2. extract() 返回一个包含有字符串的列表,配合[0]使用
3. extract_first() 返回列表中的*个字符串,列表为空没有返回None
4. get() 提取列表中第1个文本内容(等同于extract_first())

scrapy.Request发送post请求
我们知道可以通过scrapy.Request()指定method、body参数来发送post请求;但是通常使用scrapy.FormRequest()来发送post请求
1
发送post请求
注意:scrapy.FormRequest()能够发送表单和ajax请求,参考阅读 https://www.jb51.net/article/146769.htm

response响应
response.url:当前响应的url地址

1. response.request.url:当前响应对应的请求的url地址
2. response.headers:响应头
3. response.requests.headers:当前响应的请求头
4. response.body:响应体,也就是html代码,byte类型
5. response.status:响应状态码

Cookie
1.在settings.py中通过设置COOKIES_DEBUG=TRUE 能够在终端看到cookie的传递传递过程
2.如果start_url地址中的url是需要登录后才能访问的url地址,则需要重写3.start_request方法并在其中手动添加上cookie
4.如果重新start_requests()方法,则需要去掉start_urls变量

参数解释
中括号里的参数为可选参数
callback:表示当前的url的响应交给哪个函数去处理
meta:实现数据在不同的解析函数中传递,meta默认带有部分数据,比如下载延迟,请求深度等
dont_filter:默认为False,会过滤请求的url地址,即请求过的url地址不会继续被请求,对需要重复请求的url地址可以把它设置为Ture,比如贴吧的翻页请求,页面的数据总是在变化;start_urls中的地址会被反复请求,否则程序不会启动
method:指定POST或GET请求
headers:接收一个字典,其中不包括cookies
cookies:接收一个字典,专门放置cookies
body:接收json字符串,为POST的数据,发送payload_post请求时使用(在下一章节中会介绍post请求)
注意:解析函数中的yield能够传递的对象只能是:BaseItem, Request, dict, None
meta参数的使用
meta的作用:meta可以实现数据在不同的解析函数中的传递
在爬虫文件的parse方法中,提取详情页增加之前callback指定的parse_detail函数:

def parse(self,response):

yield scrapy.Request(detail_url, callback=self.parse_detail,meta={“item”:item})

def parse_detail(self,response):
#获取之前传入的item
item = resposne.meta[“item”]

注意
1. meta参数是一个字典
2. meta字典中有一个固定的键proxy,表示代理ip,关于代理ip的使用我们将在scrapy的下载中间件

管道 piplines.py
管道的基本使用:
1. 完善pipelines.py中的process_item函数
2. 在settings.py中设置开启pipeline
3. pipeline在setting中键表示位置(即pipeline在项目中的位置可以自定义),值表示距离引擎的远近,越近数据会越先经过:权重值小的优先执行
4. 1. 有多个pipeline的时候,process_item的方法必须return item,否则后一个pipeline取到的数据为None值
5. pipeline中process_item的方法必须有,否则item没有办法接受和处理
6. process_item方法接受item和spider,其中spider表示当前传递item过来的spider

pipeline中常用的方法:
process_item(self,item,spider):
管道类中必须有的函数
实现对item数据的处理
必须return item
open_spider(self, spider): 在爬虫开启的时候仅执行一次
close_spider(self, spider): 在爬虫关闭的时候仅执行一次
开启管道
在settings.py设置开启pipeline
1
ITEM_PIPELINES = {
‘myspider.pipelines.ItcastFilePipeline’: 400, # 400表示权重
‘myspider.pipelines.ItcastMongoPipeline’: 500, # 权重值越小,越优先执行!
}

多个管道的开启作用
1. 不同的pipeline可以处理不同爬虫的数据,通过spider.name属性来区分
2. 不同的pipeline能够对一个或多个爬虫进行不同的数据处理的操作,比如一个进行数据清洗,一个进行数据的保存
3. 同一个管道类也可以处理不同爬虫的数据,通过spider.name属性来区分

MongoDB 持久化
# 【1】settings.py中添加
ITEM_PIPELINES = {
# 添加MongoDB管道
‘Tencent.pipelines.TencentMongoPipeline’: 400,
}
MONGO_HOST = ‘127.0.0.1’
MONGO_PORT = 27017
MONGO_DB = ‘tencentdb’
MONGO_SET = ‘tencentset’

# 【2】pipelines.py中新建MongoDB管道类
from .settings import *
import pymongo

class TencentMongoPipeline:
def open_spider(self, spider):
self.conn = pymongo.MongoClient(MONGO_HOST, MONGO_PORT)
self.db = self.conn[MONGO_DB]
self.myset = self.db[MONGO_SET]

def process_item(self, item, spider):
self.myset.insert_one(dict(item))

Json 持久化
import json

class WangyiPipeline(object):

def open_spider(self, spider):
if spider.name == ‘job’:
self.file = open(‘wangyi.json’, ‘w’)

def process_item(self, item, spider):
if spider.name == ‘job’:
item = dict(item)

str_data = json.dumps(item, ensure_ascii=False) + ‘,\n’

self.file.write(str_data)

return item

def close_spider(self, spider):
if spider.name == ‘job’:
self.file.close()

MySql 持久化
1)MySQL建表

create database tencentdb charset utf8;
use tencentdb;
create table tencenttab(
job_name varchar(200),
job_type varchar(200),
job_duty varchar(2000),
job_require varchar(2000),
job_add varchar(100),
job_time varchar(100)
)charset=utf8;

2)MySql数据持久化

# 【1】settings.py添加
ITEM_PIPELINES = {
# 在原来基础上添加MySQL的管道
‘Tencent.pipelines.TencentMysqlPipeline’: 200,
}
MYSQL_HOST = ‘127.0.0.1’
MYSQL_USER = ‘root’
MYSQL_PWD = ‘123456’
MYSQL_DB = ‘tencentdb’
CHARSET = ‘utf8’

# 【2】pipelines.py新建MySQL管道类
from .settings import *
import pymysql

class TencentMysqlPipeline:
def open_spider(self, spider):
self.db = pymysql.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PWD, MYSQL_DB, charset=CHARSET)
self.cur = self.db.cursor()
self.ins = ‘insert into tencenttab values(%s,%s,%s,%s,%s,%s)’

def process_item(self, item, spider):
li = [
item[‘job_name’],
item[‘job_type’],
item[‘job_duty’],
item[‘job_require’],
item[‘job_add’],
item[‘job_time’],
]
self.cur.execute(self.ins, li)
self.db.commit()

return item

def close_spider(self, item, spider):
self.cur.close()
self.db.close()

进阶:mysql连接池
Csv持久化
piplines.py
import csv

class LianjiaspiderPipeline(object):
def open_spider(self, spider):
if spider.name == “home”:
self.file = open(‘lianjia.csv’, ‘w’, encoding=”utf-8″)
self.f_csv = csv.writer(self.file)
headers = [‘地址’, ‘总价’, ‘单价’, ‘户型’, ‘面积’, “朝向”, “楼层”, “装修程度”, “详情页url”]
self.f_csv.writerow(headers)

def process_item(self, item, spider):
if spider.name == “home”:
data = [item[“address”], item[“price”], item[“unit_price”], item[“door_model”], item[“area”],
item[“direction”], item[“floor”], item[“decorate”], item[“info_url”]]
self.f_csv.writerow(data)
print(data)
return item

def close_spider(self, spider):
if spider.name == “home”:
self.file.close()

settings.py
# 管道
ITEM_PIPELINES = {
‘LianJiaSpider.pipelines.LianjiaspiderPipeline’: 300,
}

中间件 middleware.py
中间件的分类
1.下载器中间件
2.爬虫中间件

Scrapy中间的作用(预处理Request和Response对象)
1. 对header以及cookie进行更换和处理
2. 使用代理ip等
3. 对请求进行定制化操作,

但在scrapy默认的情况下 两种中间件都在middlewares.py一个文件中

爬虫中间件使用方法和下载中间件相同,且功能重复,通常使用下载中间件

Downloader Middlewares默认的方法:
process_request(self, request, spider):

当每个request通过下载中间件时,该方法被调用。
2. 返回None值:没有return也是返回None,该request对象传递给下载器,或通过引擎传递给其他权重低的process_request方法
3. 返回Response对象:不再请求,把response返回给引擎
4. 返回Request对象:把request对象通过引擎交给调度器,此时将不通过其他权重低的process_request方法
process_response(self, request, response, spider):

当下载器完成http请求,传递响应给引擎的时候调用
2. 返回Resposne:通过引擎交给爬虫处理或交给权重更低的其他下载中间件的process_response方法
3. 返回Request对象:通过引擎交给调取器继续请求,此时将不通过其他权重低的process_request方法
在settings.py中配置开启中间件,权重值越小越优先执行

fake_useragent
middlewares.py
from fake_useragent import UserAgent
class RandomUserAgentMiddleware(object):
def process_request(self, request, spider):
ua = UserAgent()
request.headers[‘User-Agent’] = ua.random

settings.py
DOWNLOADER_MIDDLEWARES = {
‘xxx项目名.middlewares.RandomUserAgentMiddleware’: 300,
}

注意:UserAgent中间件设置为None,这样就不会启用,否则默认系统的这个中间会被启用。

ip_proxy
方法一【免费代理】:
settings.py
DOWNLOADER_MIDDLEWARES = {
‘项目名.middlewares.RandomProxy’: 543,
}
PROXY_LIST =[
{“ip_port”: “123.207.53.84:16816”, “user_passwd”: “morganna_mode_g:ggc22qxp”},
# {“ip_port”: “122.234.206.43:9000”},
]

middlewares.py
from 项目名.settings import PROXY_LIST

class RandomProxy(object):

def process_request(self, request, spider):
proxy = random.choice(PROXY_LIST)
print(proxy)
if ‘user_passwd’ in proxy:
# 对账号密码进行编码,python3中base64编码的数据必须是bytes类型,所以需要encode
b64_up = base64.b64encode(proxy[‘user_passwd’].encode())
# 设置认证
request.headers[‘Proxy-Authorization’] = ‘Basic ‘ + b64_up.decode()
# 设置代理
request.meta[‘proxy’] = proxy[‘ip_port’]
else:
# 设置代理
request.meta[‘proxy’] = proxy[‘ip_port’]

方法二【收费代理】:
收费代理ip:

# 人民币玩家的代码(使用abuyun提供的代理ip)
import base64

# 代理隧道验证信息 这个是在那个网站上申请的
proxyServer = ‘http://proxy.abuyun.com:9010’ # 收费的代理ip服务器地址,这里是abuyun
proxyUser = 用户名
proxyPass = 密码
proxyAuth = “Basic ” + base64.b64encode(proxyUser + “:” + proxyPass)

class ProxyMiddleware(object):
def process_request(self, request, spider):
# 设置代理
request.meta[“proxy”] = proxyServer
# 设置认证
request.headers[“Proxy-Authorization”] = proxyAuth

检测代理ip是否可用
在使用了代理ip的情况下可以在下载中间件的process_response()方法中处理代理ip的使用情况,如果该代理ip不能使用可以替换其他代理ip

class ProxyMiddleware(object):
……
def process_response(self, request, response, spider):
if response.status != ‘200’:
request.dont_filter = True # 重新发送的请求对象能够再次进入队列
return requst

settings.py
DOWNLOADER_MIDDLEWARES = {
‘myspider.middlewares.ProxyMiddleware’: 543,
}

Scrapy-redis
settings.py 文件配置[注意:scrapy-redis 与 bloomfilter 二者只能选其一使用]
# scrapy-redis分布式配置 pip install scrapy-redis
# 重新指定调度器: 启用Redis调度存储请求队列!!!
SCHEDULER = “scrapy_redis.scheduler.Scheduler”
# 重新指定去重机制: 确保所有的爬虫通过Redis去重!!!
DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter”

# redis配置
REDIS_HOST = ‘127.0.0.1’ # ip
REDIS_PORT = 6379 # 端口
# REDIS_PARAMS = {
# ‘password’: ”, # 密码
# }

Scrapy-bloomfilter布隆过滤器
settings.py文件配置
# 布隆过滤器配置 pip install scrapy-redis-bloomfilter
# 重新指定调度器
SCHEDULER = “scrapy_redis_bloomfilter.scheduler.Scheduler”
# 重新指定去重机制
DUPEFILTER_CLASS = “scrapy_redis_bloomfilter.dupefilter.RFPDupeFilter”
# 使用哈希函数的数量,默认为6
BLOOMFILTER_HASH_NUMBER = 6
# 使用Bloomfilter的Redis内存,30表示2^30 = 128MB,默认为30
BLOOMFILTER_BIT = 30

设置 settings.py
常用变量
设置数据导出编码(主要针对于json文件)
FEED_EXPORT_ENCODING = ‘utf-8’
设置User-Agent
USER_AGENT = ”
设置*大并发数(默认为16)
CONCURRENT_REQUESTS = 32
下载延迟时间(每隔多长时间请求一个网页)
DOWNLOAD_DELAY = 0.5
请求头
DEFAULT_REQUEST_HEADERS = {‘Cookie’ : ‘xxx’}
添加项目管道
ITEM_PIPELINES = {‘目录名.pipelines.类名’ : 优先级}
COOKIES_ENABLED = False

启动运行
方法一【运行单个爬虫文件】:
在根目录下创建start.py

from scrapy import cmdline

cmdline.execute(“scrapy crawl hot”.split())
# cmdline.execute(“scrapy crawl hot -o hot.csv”.split()) # 导出csv

# cmdline.execute(“scrapy crawl hot -o hot.json”.split()) # 导出json

# 注意: settings.py中设置导出编码 – 主要针对json文件
FEED_EXPORT_ENCODING = ‘utf-8’

Excel打开csv时出现乱码

解决办法:用记事本打开CSV,文件菜单中另存为UTF-8保存
方法二【 串行 运行完*个才会运行下一个】:
在根目录下创建main.py

from scrapy.cmdline import execute

execute(“scrapy crawl 爬虫文件名1”.split())
execute(“scrapy crawl 爬虫文件名2”.split())

方法三【在进程里面跑多个爬虫】:
在根目录下创建main.py

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

settings = get_project_settings()

crawler = CrawlerProcess(settings)

crawler.crawl(‘爬虫文件名1’)
crawler.crawl(‘爬虫文件名2’)

crawler.start()
crawler.start()

UE4 Python脚本编辑器扩展

UE4 Python脚本编辑器扩展

Python+编辑器扩展

1. 各种菜单的扩展
1.1 主菜单内添加一个子菜单
mainMenu = menus.find_menu(‘LevelEditor.MainMenu’) // 找到主菜单

ownerName = mainMenu.get_name()
# 该名称用于标识一个菜单下的分区名,如果menu的sectionName一致,它们会被放在一起
sectionName = ‘PythonTools’
subMenuName = ‘MenuTest’
subMenuLabel = ‘MenuTest1’
subMenuTip = ‘This is menutest1’
menus.add_sub_menu(ownerName, sectionName, subMenuName, subMenuLabel, subMenuTip)
# 刷新窗口
menus.refresh_all_widgets()

想要查看ue编辑器内的各个sectionname,可以在EditorPreference中的Misc中打开相应配置,打开一个菜单时会刷新对应的widget,如果想要窗口全部刷新则可以执行如下python命令
py unreal.ToolMenus.get().refresh_all_widgets()

1.2 菜单项下添加一个按钮
menus = unreal.ToolMenus.get()
# 根据上面的subMenuName找到目标菜单
targetMenu = menus.find_menu(‘LevelEditor.MainMenu.MenuTest’)

menuEntry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.MENU_ENTRY)
menuEntry.set_label(‘Test Button 1’)
menuEntry.set_string_command(unreal.ToolMenuStringCommandType.PYTHON, ”, ‘print(‘this is button 1′)’)

sectionname = ”
targetMenu.add_menu_entry(sectionname, menuEntry)
menus.refresh_all_widgets()

按钮的命令:
unreal.ToolMenuStringCommandType.PYTHON,后面的字符串为python代码;
unreal.ToolMenuStringCommandType.COMMAND,后面的字符串为cmd命令,如使用py xxx.py执行脚本;
等同于输出日志中的python控制台和cmd控制台的py命令;

1.3 为ToolBar添加按钮
# 和上面的两个区别,首先是targetMenu,然后是Entry的类型
targetMenu = menus.find_menu(‘LevelEditor.ToolEditorToolBar’)
menuEntry = unreal.ToolMenuEntry(type=unreal.MultiBlockType.TOOL_BAR_BUTTON)
1
2
3
1.4 内容浏览器右键菜单扩展
targetMenu = unreal.ToolMenus.get(‘ContentBrowser.FolderContextMenu’)
entry = unreal.ToolMenuEntry(type=unreal.MultiBlockType,MENU_ENTRY)

# 选中的资源
unreal.ContentBrowserAssetContextMenuContext.get_selected_objects()

1.5 关卡视口中actor右键菜单
可以用如下方式获取选中的actor,但是无法像蓝图一样将actor强转到相应的派生类,因此也就无法获取到实例actor的属性以及不能调用相应的函数;目前的python是不支持这个的,可参考:https://answers.unrealengine.com/questions/938515/casting-a-blueprint-in-python.html;
只能调用actor类已有的内置函数,如set_actor_location()等;

assets = unreal.EditorLevelLibrary.get_selected_level_actors()
for actor in assets:
1
2
但是可以修改bp的默认值,如下所示:
我们需要调用unreal.get_default_object来获取CDO(Class Default Object),然后使用set_editor_property来完成功能;

bp_class = unreal.load_class(None, ‘/Game/NewBlueprint.NewBlueprint_C’)
cdo = unreal.get_default_object(bp_class)
cdo.set_editor_property(‘var’, 102)
cdo.call_method(‘TestFunc’, (actor,))

上述列出的问题虽然python内不能解决,但是能够通过蓝图扩展来完成;
基于python的扩展依然还只是在pie中使用;

2. 基础实践
2.1 日志系统
unreal.log() : python中的print也会在内部通过unreal.log()来处理
unreal.log_warning()
unreal.log_error()
2.2 处理资源
如果需要在项目中处理资源,必须使用Unreal Python API来完成,而不能使用Python内置模块来处理磁盘资源文件,比如资源的移动,如果不适用unreal的api则会导致引用失效,所以要尽量使用unreal.EditorAssetLibrary或unreal.AssetTools

尽可能使用虚幻类型
比如数学类等,要尽可能使用Unreal API提供的类型,如unreal.Vector()

2.3 使用json配置来管理各种扩展
os.open/read/write
import json
json.dumps/loads

3.其它常用api
3.1 资源相关
资源相关的api都在这个库里:unreal.EditorAssetLibrary
资源的保存:save_asset()

3.2 工程路径
系统库:unreal.SystemLibrary
获取项目路径:get_project_directory()

4.结合pyqt5的进阶实践
本想使用ue4的api来打开一个文件对话框,但是没有找到,网上有一些使用C++的扩展;
因此就想到了pyqt5也可以完成,而且ue4也可以调用python,这样就不用在C++层处理了,但是这只能用于编辑器模式下;

4.1 打开一个文件对话框
import unreal
import os
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QToolTip, QPushButton, QMessageBox, QDesktopWidget, QFileDialog, QLabel)

class Example(QFileDialog):

def __init__(self):
super().__init__()
self.open_folder()

def open_folder(self):
path = QFileDialog.getExistingDirectory(self, u’选择文件夹’, unreal.SystemLibrary.get_project_directory())
print(path)

app = QApplication(sys.argv)
ex = Example()
sys.exit(app.quit())

5. 常见问题
5.1 Python missing classes from unreal module
一些模块没有找到是因为我们需要安装对应的插件
我们可以使用如下方式可以遍历到unreal下所有的子模块

import unreal
moduels = dir(unreal)
for module in modules:
print(module)

Python基础入门:九大必学点

Python基础入门:九大必学点

小编整理了一天,希望对想学习的朋友用,认真看与学,你就能敲会简单的码,学习上也就能事功半倍,下面就是本章的内容大概,喜欢就一定要收藏起来。

缩进
Python 函数没有明显的 begin 和 end,没有标明函数的开始和结束的花括号。唯一的分隔符是一个冒号 (?,接着代码本身是缩进的。

例子:

#函数
def func(value):
print value #缩进
if value == 1:
value += 1
elif value == 2:
pass
else:
value += 10

标识符
变量是标识符的例子。 标识符 是用来标识 某样东西 的名字。在命名标识符的时候,你要遵循这些规则:

1.python中的标识符是区分大小写的。

2.标示符以字母或下划线开头,可包括字母,下划线和数字,大小写敏感

3.以下划线开头的标识符是有特殊意义的。

•以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用“from xxx import *”而导入;
•以双下划线开头的(foo)代表类的私有成员;
•以双下划线开头和结尾的(foo)代表python里特殊方法专用的标识,如__init()代表类的构造函数。

4.标识符不能是保留字

and elif global or yield
assert else if pass
break except import print
class exec in raise
continue finally is return
def for lambda try
del from not while

变量
赋值语句
•赋值语句建立对象引用值
•变量名在首次赋值时会被建立
•变量名在引用前必须先赋值,不能引用未声明赋值的变量

赋值方式
•简单赋值
Variable(变量)=Value(值)
s = ‘spam’

•多变量赋值
python中原始的元组和列表赋值语句形成,*后已被通用化,以接受右侧可以是是任何类型的序列,只要长度相等即可。注意,长度一定相等
Variable1,variable2,…=Value1,Value2,…
s,h = ‘a’,‘b’ 元组赋值,位置性 【常用】
[s,h] =[‘a’,‘b’] 列表赋值,位置性
a,b,c,d = ‘spam’ 序列赋值,通用性
a,*b = ‘spam’ 拓展序列解包(python3)

•多目标赋值
a=b=variable
s = h = ‘spam’ 多目标赋值
注意:多个变量内存中指向同一对象,对于可变类型需要,修改一个会对其他造成影响

•自变赋值
如+=,-=,*=等。
在自变赋值中,python仅计算一次,而普通写法需计算两次;
自变赋值会修改原始对象,而不是创建一个新对象。
s +=42 增强赋值
x += y
优点:
程序员输入更少
左侧只需计算一次,优化技术自动原处修改,更快
l +=[] 原处修改
l = l+[] 复制,生成新的对象

运算符
一个表达式可以分解为运算符和操作数

运算符 的功能是完成某件事,它们由如+这样的符号或者其他特定的关键字表示
运算符需要数据来进行运算,这样的数据被称为 操作数
运算符优先顺序列表(从*高到*低)
运算符的描述

‘expr’ 字符串转换
{key:expr,…} 字典
[expr1,expr2…] 列表
(expr1,expr2,…) 元组
function(expr,…) 函数调用
x[index:index] 切片
x[index] 下标索引取值
x.attribute 属性引用
~x 按位取反
+x,-x 正,负
x**y 幂
x*y,x/y,x%y 乘,除,取模
x+y,x-y 加,减
x<<y,x>>y 移位
x&y 按位与
x^y 按位异或
x|y 按位或
x<y,x<=y,x==y,x!=y,x>=y,x>y 比较
x is y,x is not y 等同测试
x in y,x not in y 成员判断
not x 逻辑否
x and y 逻辑与
x or y 逻辑或
lambda arg,…:expr Lambda匿名函数
结合规律

运算符通常由左向右结合,即具有相同优先级的运算符按照从左向右的顺序计算

计算顺序
默认地,运算符优先级表决定了哪个运算符在别的运算符之前计算。然而,如果你想要改变它们的计算顺序,你得使用圆括号。好的做法:默认对复杂的运算加括号,而不是依赖于默认结合和计算顺序

真值
真值测试
•任何非零数字或非空对象都为真
•数字零,空对象以及特殊对象None都为假
•比较和相等测试都会递归地运用到数据结构中
•比较和相等测试会返回True或False
真值表

对象/常量 值
“” 假
“string” 真
0 假
2>=1 真
-2<=-1 真
()空元组 假
[]空列表 假
{}空字典 假
None 假

布尔表达式
三种布尔表达式运算符

x and y
x or y
not x

比较
•数字通过相对大小进行比较
•字符串时按照字典顺序的,一个字符一个字符比较
•列表和元组从左到右对每部分的内容进行比较
•字典通过排序后的键值列表进行比较
•数字混合类型比较在python3是错误的,但是python2.6支持,固定但任意的排序规则
布尔数
•有两个永远不改变的值True,False
•布尔是整型的子类,但不能被再继承
•没有__nonzero__()方法的对象的默认值是True
•对于值为0的任何数字或空集,值False
•在数学运算中,Bollean值的True和False分别对应于1和0

基本控制流
if
基本的条件测试语句,用来判断可能遇到的不同情况,并针对不同的情况进行操作
基本形式

if <条件>:
<语句>
elif <条件>:
<语句>
else:
<语句>

注意
python根据缩进判断, elif和else部分是可选的

例子:

a = 1
b = 2
c = 3;d=4 #两个放一句用分号隔开,不过建议分行
if a < b and c < d:
print(“branch a”)
elif a == b:
print(“branch b”)
else:
print(“branch c”)
switch

python 本身没有 switch 语句,若需要,用if/elif/else实现完成同样的工作,某些情况可以考虑用字典
也可以用dict的形式
if/else三元运算符
A = ((X and Y) or Z)
A = Y if X else Z
例: a = ‘t’ if x else ‘a’
for
在这里插入图片描述

基本语法
循环控制语句,可以用于循环遍历某一序列
else块可选,在循环终止的时候执行,若是break终止循环,else不执行
格式:

for <对象变量> in <对象集合>:
if<条件>:
break
if<条件>:
continue
<其他语句>
else:
<其他语句>

注意:
1.对象集合可以是列表,字典以及元组等
2.for…in循环对于任何序列都适用
3.for遍历一个字典时,遍历的是字典的键
•rang & xrange
可以通过range()函数产生一个整数列表,完成计数循环
range([start,] stop[, step])
start可选参数,起始数
stop终止数,若为x,产生从0-(x-1)的整数列表
step可选参数,步长,未写默认为1
range(1,5) 包含序列为 [1,2,3,4]
xrange和range区别
(python3.x的可无视)

在Range的方法中,它会生成一个list的对象,但是在XRange中,它生成的却是一个xrange的对象,当返回的东西不是很大的时候,或者在一个循环里,基本上都是从头查到底的情况下,这两个方法的效率差不多。但是,当返回的东西很大,或者循环中常常会被Break出来的话,还是建议使用XRange,这样既省空间,又会提高效率。

>>> print range(1, 5)
[1, 2, 3, 4]
>>> print xrange(1, 5)
xrange(1, 5)

在上面语句中,range返回了一个普通List,而xrange返回了一个特定的xrange类型的对象。由于 xrange 方法也创建整数 list(其使用相同参数),所以它与 range 方法非常相似。但是,xrange 方法仅在需要时才在 list 中创建整数。当需要迭代大量整数时,xrange 方法更适用,因为它不会创建*大的 list,那样会消耗大量计算机内存。
while
与if语句类似,含一个条件测试语句,循环,允许重复执行一个语句块。

可选else语句块,同for的else块。

格式:

while <条件>:
if <条件>:
break
if <条件>:
continue
<其他语句>
else:
<语句>

说明:

•while循环条件变为False的时候,else块才被执行
•若是使用break结束循环,while可选的else块不执行
•python没有do while或do until循环语句
break & continue & pass
break,终止循环语句,停止循环,若是for/while循环中终止,其else不执行

continue,结束当前,进入下一轮循环 – 跳到*近所在循环的开头处(来到循环首行)

pass 什么事也不做,只是空占位语句,它用于那些语法上必须要有什么语句,但程序什么也不做的场合

循环else块 :只有循环正常离开时才会执行,即

如果你从for或while循环中break终止 ,任何对应的循环else块将不执行。记住,break语句也可以在for循环中使用

编写循环的技巧
在迭代过程中修改迭代序列不安全(只有在使用链表这样的可变序列时才会有这样的情况)。如果你想要修改你迭代的序列(例如,复制选择项),你可以迭代它的复本。使用切割标识就可以很方便的做到这一点

>>> for x in a[:]: # make a slice copy of the entire list
… if len(x) > 6: a.insert(0, x)

在字典中循环时,关键字和对应的值可以使用 iteritems() 方法同时解读出来

>>> knights = {‘gallahad’: ‘the pure’, ‘robin’: ‘the brave’}
>>> for k, v in knights.iteritems():
… print k, v

gallahad the pure
robin the brave

在序列中循环时,索引位置和对应值可以使用 enumerate() 函数同时得到。

>>> for i, v in enumerate([‘tic’, ‘tac’, ‘toe’]):
… print i, v

DevOps和云计算是什么关系 该如何学好云计算

DevOps和云计算是什么关系?该如何学好云计算?云计算是当前市场上的热门技术,也是未来互联网发展的主要趋势。随着越来越多的企业将业务迁移到云上以及云应用的不断增多,云计算人才成为香饽饽,各大企业纷纷祭出高薪抢夺人才。很多人现在学习云计算时会遇到DevOps,它和云计算究竟是什么关系,接下来就给大家介绍一下。

%title插图%num

DevOps的定义通常分为两个方面:

1)开发和运维之间更友好。在使用这个定义的企业中,IT运维是单独存在的,但是对开发人员来说是非常友好的。例如,DevOps在基础设施的配备中为开发人员提供了自助目录,也为新代码的部署提供了技术支持的通道。

2)DevOps强调独立的综合型团队。在使用这个定义的企业中,开发人员承担运维的责任,反之亦然。

云计算不是一种全新的网络技术,而是一种全新的网络应用概念,云计算的核心概念就是以互联网为中心,在网站上提供快速且安全的云计算服务与数据存储,让每一个使用互联网的人都可以使用网络上的庞大计算资源与数据中心。现阶段所说的云服务是指分布式计算、效用计算、负载均衡、并行计算、网络存储、热备份冗杂和虚拟化等计算机技术混合演进并跃升的结果。

DevOps和云计算的出现是由于社会行为的变化以及对企业响应的相应调整。DevOps是一次高级、快速且不间断的软件程序传输过程,云平台是驱动软件实施敏捷性的性能平台。云计算推动IT转型,通过使用具和自动化技术,帮助企业缩减了工作流程,简化并嵌入DevOps流程,提高了效率,从而实现了真正意义上的变革。这两个功能互为关联,以帮助企业控制开发并利用性能,甚至消除了容易出错的环境。

如果你想成为一个优秀的云计算人才,一定要会借助DevOps的优势。如果你想快速入行UI设计,可以专业学习一下,千万不要错过学习的机会,让自己理论与实战兼备,成为企业急需的高薪精英!

云计算人才必须掌握什么 怎么学Linux性能优化

云计算人才必须掌握什么?怎么学Linux性能优化?Linux是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统,具有免费使用和自由传播的特性。随着开源软件的发展以及云计算技术的革新,Linux成为云计算人才必须要掌握的技能之一。在接下来的分享中,千锋小编就给大家简单介绍一下Linux性能优化之IO子系统。

 

很多同学听过IO流,即以流的方式进行输入输出,其中流是一种抽象的概念,它代表了数据的无结构化传递。IO系统,英文全称为“Input output system”,中文全称为“输入输出系统”,由输入输出控制系统和外围设备两部分组成,是计算机系统的重要组成部分。

%title插图%num

作为Linux服务器来讲,*大的两个IO类型是磁盘IO和网络IO。一个完整的IO系统过程如下:

1)一个用户进程通过write()系统调用发起写请求;

2)内核更新对应的page cache;

3)pdflush内核线程将page cache写入至磁盘中;

4)文件系统层将每一个block buffer存放为一个bio结构体,并向块设备层提交一个写请求;

5)块设备层从上层接受到请求,执行IO调度操作,并将请求放入IO请求队列中;

6)设备驱动(如SCSI或其他设备驱动)完成写操作;

7)磁盘设备固件执行对应的硬件操作,如磁盘的旋转、寻道等,数据被写入到磁盘扇区中。

block layer处理bio请求,并将这些请求链接成一个队列,称作IO请求队列,这个连接的操作就称作IO调度(也叫IO elevator即电梯算法)。bio结构体是file system layer到block layer的接口。

IO调度器的总体目标是减少磁盘的寻道时间(因此调度器都是针对机械硬盘进行优化的),IO调度器通过两种方式来减少磁盘寻道:合并和排序。

合并即当两个或多个IO请求的是相邻的磁盘扇区,通过合并请求,多个IO请求只需要向磁盘发送一个请求指令,减少了磁盘的开销。

排序就是将不能合并的IO请求,根据请求磁盘扇区的顺序,在请求队列中进行排序,使得磁头可以按照磁盘的旋转顺序的完成IO操作,可以减小磁盘的寻道次数。

想要优化IO系统性能,我们可以采用以下几种方式:

1)调整buffer、提高性能,就是调整队列数以及增加预读数。

增加队列长度:/sys/block/vda(特定某设备)/queue/nr_requests

增加预读数:/sys/block/vda(特定某设备)/queue/read_ahead_kb

2)修改CFQ,以调节其性能,涉及参数文件:/sys/block/vda/queue/iosched/。

比如对CFQ来讲,有以下几个值可以调整:

back_seek_max

反向寻道可能有负面影响,负载小的时候可以启用,否则不要使用反向寻道太多值。

back_seek_penal

反向寻道做惩罚,如果不得不使用反向寻道的话,那么必须对其做出一定惩罚,一旦做完惩罚之后,必须要正向寻道更多次数。

fifo_expire_async

用来控制异步请求等待时间长度,默认是250毫秒,过期之后无法满足的异步请求将会被移动到调度队列中,也就意味着要重新调度,通常这些值不需要调整。

除了以上方法,IO优化的方法还有很多,大致思路是*好换SSD、调整raid级别、选择IO调度器、根据场景选择合适的文件系统、配置选定调度器的参数、使用工具进行分析优化结果是否理想、写在开机启动项里。

想了解更多Linux性能优化技巧或者快速入门云计算,你可以选择专业学习一下。让自己求职起点更高、就业速度更快!

关于Android Auto:你需要知道的全都在这了!

前言

我是Android Auto的忠实粉丝。实际上,我是一个狂热的粉丝,在高速公路上飞行的时候,任何能让人们的手机从胖胖的手指中拿出来的东西。或者在红绿灯处。在任何地方,真的 好消息是我们有比以往更多的选择。车载和蓝牙都可以。Apple的CarPlay并不太糟糕。

但Android Auto是所有信息娱乐系统应该努力的方向。它易于使用。看起来很好。

*重要的是,它不仅仅是让你在驾驶时使用手机变得不切实际 – 它主要是因为你甚至不想碰这个东西。

但谷歌实施汽车模式并不完美。因此,当我们进入新一年的硬件和服务时 – 充分了解即将发生的事情可能会在我们关注时改变我们的观点 – 让我们来看看哪些有效,哪些需要改进。

Android Auto是在您的汽车中使用手机*安全,*简单的方式。

Android Auto:基础知识

你的车没有“运行”Android Auto。它并非天然烘焙到您的车辆中。然而不,无论您是拥有工厂信息娱乐系统还是售后市场主管部门,您仍然需要与蹩脚的内置用户界面抗衡。这只是生活中的一个事实。

Android Auto是独立的,并与工厂体验一起运行。它由您的Android手机提供支持。这些应用程序存在于您的Android手机上。这是一件好事。因为任何可以使用Android Auto的汽车都可以使用您的Android Auto。你的应用。你的音乐。你的经历。

Android Auto上的Google地图。

Android Auto在过去一年左右的*大变化实际上是在2016年底。在此之前,Android Auto是一款应用程序,可以将自己投射到汽车的信息娱乐屏幕上,只有那个屏幕。你的手机会变暗,有效地(但不是完全地)将你锁定,同时进行繁重的工作并将驾驶员友好的UI投射到车内。

现在?Android Auto 作为一款出色的基于手机的汽车模式应用启动。无论你的车多大了,或者它是否有收音机都没关系,更不用说带有7英寸显示屏的车。没有昂贵的售后安装,也没有必要处理可能笨重的布线。(更多关于此的内容。)

但是,如果你这样做有一个兼容的头单元,你会得到一个更大,更好的体验。更大的专辑封面。更大的地图。大触摸目标。更内置的东西,对我而言,让它感觉像你使用的东西,而不一定。你现在必须插上你的手机才能工作,不过今年它会开始改变,因为无线连接终于看到了光明的一天。

但总的来说,无论您使用的是Android Auto的手机版还是内置品牌,它们的体验大多相​​同。

当然,您可以使用Android Auto与您的汽车交谈。如果你的方向盘上有一个“对话”按钮,请务必使用它。如果不这样做,您可以点击屏幕上的麦克风按钮。或者您可以将手机设置为响应“OK,Google”,并自动处理这些事情。

哪些车内置了Android Auto功能?很多,随着更多的添加。(不过谷歌表示超过400款。)先锋,建伍,索尼等产品的售后市场选择让几乎任何人都可以获得完整的Android Auto体验。

但是有一些坚持。宝马?算了吧。奔驰?只有你很幸运。由于某些原因,马自达仍在努力添加Android Auto。

选择要在Android Auto上使用的应用就像指点一样简单。

Android Auto:应用程序

适用于内置版Android Auto的每个应用均适用于Android Auto的手机版。那是因为Android Auto没有真正的特殊应用程序。相反,将AA视为现有应用程序的框架,将功能重新设计为适合汽车的界面。谷歌地图是谷歌地图 – 它也适用于Android Auto。Pocket Casts是同样出色的podcatcher,也适用于Android Auto。Waze是Waze。

您可以将Android Auto应用程序(嗯,也适用于Android Auto的应用程序)分为三类:娱乐,消息和地图。那里有多少?我不知道。Google的促销页面不完整。但它是一个相当深的存储库。

并非每个应用都适用于Android Auto – 与Android Auto配合使用的应用必须遵循一套非常具体的指南,以便于使用和安全。开车时你不会看视频。(反正你真的不应该。)

更复杂的是,Uber流行的Waze – 它一直是手机上的地图应用程序 – 可以在Android Auto上实现全屏体验,但不适用于Android Auto的手机版本。去搞清楚。

Android自动主屏幕。

Android自动用户界面

您可以将Android Auto视为系统中的系统。它有一个背景和一种主屏幕。但是,您一次只能使用一个应用程序,只有*少的通知,而且只能使用已扩展到Android Auto的消息应用程序。当然,重点是尽可能让一些分心,同时仍然能够使用这个东西。

主要选项都停靠在屏幕的底部。导航。电话。你的主屏幕。音频。这是您在应用程序之间切换的地方,如果您在给定类别中有多个应用程序选择器,则打开应用程序选择器。(你可能会这样做。)

主屏幕可根据您的Google帐户信息进行自定义。天气出现在这里。即将发生的事件。将会看到*近的呼叫(传入和传出)和消息。任何当前正在播放的媒体都在这里。这一切都以易于阅读,易于处理的方式完成。

Android Auto上的娱乐应用

Android Auto上的Google Play音乐。

虽然“娱乐”对于Android Auto应用程序的这个子类别(技术上它是“音频”)来说并不是一个正确的词,但它足够接近。音乐应用程序就在那里。默认情况下通常会包含Google Play音乐。正如您所期望的那样,它在Android Auto上运行良好。但它远非唯一的选择。Spotify受支持。亚马逊音乐就在那里。因此,也有潘多拉和的Deezer。和其他人一样。

Podcast应用程序 – podcatchers也属于这一类。当然,Google自有内置于Google Play音乐中。但其他应用如Pocket Casts和Dogcatcher以及BeyondPod都包含了Android Auto。

Android Auto并不关心你在听什么。它只关心它的外观。为此,每个音频应用程序的外观和工作方式几乎相同,使用相同的样式按钮和菜单。这是设计,它通常很好。

Android Auto上的消息应用程序

Skype适用于Android Auto。如果这不会给你一种恐惧感,我不知道会发生什么。但是,由于消息传递应用程序往往分散在手机或计算机上,Android Auto已经做得很好,以保持通知的黑洞 – 你永远不会离开这个 – 并将其变成安全可用的东西。

这很简单,真的。Android Auto上的消息传递应用程序以通知的形式将应用程序路由到您的屏幕 – 而不是消息本身。您可以选择是否收听。你可以选择用你的声音回复。而已。它大声朗读消息(根据消息可能很有趣,以及是否有其他人和你在一起),你可以回复。

这适用于短信,Skype,WhatsApp等任何支持Android Auto的东西。您的体验将根据消息的频率而变化 – 被轰炸在这里尤其令人讨厌 – 以及您的孩子可能在一段时间内使用多少表情符号。你还没有活过,直到Android Auto给你一个读出金星金星麒麟西瓜彩虹灯螺栓笑脸加拿大国旗拍手缺牙粪便便便便便便便便便大便便便大便烟花烟花心脏便便。

这将是一个短暂的。

您也可以使用您的声音发起消息。同样,整个想法是让你的眼睛继续前进。

在Android Auto上映射应用

您可以在Android Auto上安装任何导航应用,只要它是谷歌地图或*近的Waze。(巧合的是,这两款应用都归谷歌所有。)

这是缺乏选择的一个时期应该受到谴责。但另一方面,我不知道我使用的其他应用程序。

这两个应用程序都会挂钩到您的日历中,因此即将到来的目

你应该使用哪种 – 谷歌地图或Waze?正如我在深度探讨中解释的那样,当我不知道自己要去哪里时,我会使用谷歌地图。它有更好的路由,地图用户界面要好得多。当我知道自己在哪里时,或者在需要获得危险(或速度陷阱)的实时通知时,我会使用Waze。

Android Auto上的电话

Android Auto上的电话。

是的,您也可以通过Android Auto拨打电话。插入电源后,任何媒体音频都通过USB连接进行路由。但是电话仍然是蓝牙问题。

Android Auto的联系人和拨号程序使用您在手机上找到的相同“Material Design”方案。因为 – 等待它 – 它们与手机上的应用完全相同,只需为Android Auto重新设计输出。

如果你是静止的,你可以使用传统的拨号盘。(这里也有一个完整的键盘,虽然我很少使用它。)你可以用你的声音打电话。您可以轻松接听和拒*来电。

如果你的主机有一个内置麦克风 – 如果你正在使用全屏显示体验,你可能会这样做 – 安卓自动通过它进行路由,就像它应该的那样。

Android Auto上的Google智能助理

也许更重要的是,Android Auto可以完全访问Google智能助理。几乎任何你可以要求谷歌在你的手机上做的事情,你也可以在Android Auto中使用你的声音。

有连接灯吗?当你开车回家时命令他们开启。是否喜欢在通勤时手动设置恒温器?只需告诉Google智能助理即可。它并不关心你在哪里。它就是这样做的。

我们问Google的所有随机问题也是如此。太阳落山几点了?乔治克鲁尼上过多少部电影?狗和蜜蜂闻到了恐惧吗?内置Google智能助理意味着您可以回答任何随机问题,让您的孩子从后座向您大喊大叫。

换句话说,Google智能助理在Android Auto上与在手机上相同。因为Google智能助理已在您的手机上

什么坏了,下一步是什么

Android Auto并不完美。尽管很简单,但这里有很多变量 – 特别是当我们谈论全屏显示AA体验而不仅仅是在手机上使用它作为汽车模式时。

如果有一个单独的bugaboo应该被调用,那就是连接问题。

对于Android Auto来说真的很棒,每次都必须*次连接。

同样,这里有很多变数。手机本身。(它是USB-C?MicroUSB?制造商在感觉到电缆连接时是否做了一些愚蠢的事情?)电缆本身就是这样。(是否存在制造缺陷或其他导致其无法正常工作的财产?)无论手机连接的是什么 – 无论是工厂安装的信息娱乐系统还是售后市场主机。(那么与它们一起使用的延长线呢?)

通过添加到Android Auto的无线连接,这也是可以想象的东西将被修复 – 或者至少被绕过 – 。虽然一个人的解决是另一个问题等待发生。

我还希望看到更多控制Android Auto上显示的应用程序。例如:我的手机上有“纽约时报”应用程序,但我不一定希望它出现在我的Android自动列表中。需要有一个选项来隐藏应用程序选择器中的应用程序。我的娱乐应用程序选择器中有六个应用程序。但我只听两个 – 当我在两者之间切换时,其中一个要求我向下滚动几次。

底线

除了Gripes,这是真的:没有比Android Auto更好的车内体验。这是一个没有得到应有的信誉的宠物项目之一 – 这在这个行业中经常是罕见的。

Android Auto已经证明可以创建一个可用的无干扰界面。Android Auto易于使用。它很直观,而且很有效。这很安全。

Android Auto看起来很棒。这是设计在同一个包中同时满足表单和功能目标的更好例子之一。它使任何工厂信息娱乐用户界面看起来像它通常是完全垃圾。这让Apple的CarPlay看起来很无聊,因为它很混乱。

Android Auto现在可供Android手机使用,这对于解决路上*大障碍之一迈出了重要的一步 – 让我们的手机不受控制。

python函数lambda表达式

python函数lambda表达式

文章目录
lambda表达式的作用
lambda的语法
lambda表达式的参数形式
无参数
一个参数
默认参数
可变参数
*args
**kwargs
lambda表达式的应用
带判断的lambda表达式
列表数据按照字典键的值排序

lambda表达式的作用
对于一种函数,只有一个返回值,并且只有一句代码。无需再按def函数定义语句书写,使用lambda表达式可以简化代码。
lambda表达式也称为匿名函数。
lambda的语法
lambda 参数列表:表达式/返回值
1
其中:参数列表可有可无,可以接收任意数量的参数,但只能返回一个值。

def fun1():
return 100
print(fun1)
print(fun1())

fun2 = lambda :100
print(fun2)
print(fun2())

<function fun1 at 0x00000213E2812EA0>
100
<function <lambda> at 0x00000213E4675A60>
100

注意fun2是一个函数名字。

练习:计算三个数的平均值

# 计算三个数的平均值
def avg(a,b,c):
return ((a+b+c)/3)
print(avg(1,2,3))

avg2 = lambda a,b,c:((a+b+c)/3)
print(avg2(1,2,3))

2.0
2.0

lambda表达式的参数形式
与函数的参数形式相同

无参数
fun = lambda :100
print(fun())

100

一个参数
fun = lambda a:a*2
print(fun(‘python’))

pythonpython

默认参数
fun = lambda a,b,c=3:((a+b+c)/3)
print(fun(1,2,3))
print(fun(1,2))

2.0
2.0

可变参数
*args
接收不定长的位置参数,返回一个元组。

fun = lambda *args:args
print(fun(10,20,30))

(10, 20, 30)

**kwargs
接收不定长的关键字参数,返回一个字典。

fun = lambda **kwargs:kwargs
print(fun(name = ‘Mary’,age=20))

{‘name’: ‘Mary’, ‘age’: 20}

注意:args和kwargs名称是可变的,但一般默认是这两个。但前面一个*号和两个 *号要注意。

lambda表达式的应用
带判断的lambda表达式
fun = lambda a,b:a if a>b else b # 表示条件成立,执行前面的;条件不成立,执行后面的。

print(fun(100,50))
print(fun(50,100))

100
100

列表数据按照字典键的值排序
student = [
{‘name’:’Mary’,’age’:20},
{‘name’:’Jone’,’age’:25},
{‘name’:’Susan’,’age’:30}
]

student.sort(key=lambda x:x[‘age’])# 按照age对应的值升序排序
print(student)

student.sort(key=lambda x:x[‘age’],reverse=True)# 按照age对应的值降序排序
print(student)

[{‘name’: ‘Mary’, ‘age’: 20}, {‘name’: ‘Jone’, ‘age’: 25}, {‘name’: ‘Susan’, ‘age’: 30}]
[{‘name’: ‘Susan’, ‘age’: 30}, {‘name’: ‘Jone’, ‘age’: 25}, {‘name’: ‘Mary’, ‘age’: 20}]
————————————————
版权声明:本文为CSDN博主「能这样吃么你说」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44870115/article/details/116331647