Python中的流程控制

Python基础之:Python中的流程控制

 

文章目录
简介
while语句
if 语句
for语句
Break
Continue
pass
简介
流程控制无非就是if else之类的控制语句,今天我们来看一下Python中的流程控制会有什么不太一样的地方。

while语句
python中的while语句和其他语言没有什么不一样,我使用while语句来编写一个斐波拉赫数列:

In [56]: while x < 10 :
…: print(x)
…: x, y = y, x+y
…:

if 语句
python中的 if 可以和 elif 或者 else 配合使用:

>>> x = int(input(“Please enter an integer: “))
Please enter an integer: 42
>>> if x < 0:
… x = 0
… print(‘Negative changed to zero’)
… elif x == 0:
… print(‘Zero’)
… elif x == 1:
… print(‘Single’)
… else:
… print(‘More’)

More

if语句很简单,这里就不做过多的介绍。

for语句
Python中的for语句主要用来对序列进行迭代,比如列表或者字符串:

In [57]: ages = [ 10, 14, 18, 20 ,25]

In [58]: for age in ages:
…: print(age)
…:

遍历过程中,为了防止在遍历的时候原序列被修改,我们可以遍历序列的拷贝:

In [59]: for age in ages.copy():
…: print(age)
…:

for语句和range()函数的结合,可以得到不一样的效果。

range()用来生成给定范围内的集合:

In [61]: for age in range(5):
…: print(age)
…:

range()函数还可以带步长作为第三个参数:

In [62]: for age in range(5, 10 , 2):
…: print(age)
…:

Range()和len()组合,可以方便的变量列表:

>>> a = [‘Mary’, ‘had’, ‘a’, ‘little’, ‘lamb’]
>>> for i in range(len(a)):
… print(i, a[i])

0 Mary
1 had
2 a
3 little
4 lamb

Break
break用来跳出*近的for或者while循环。

要注意的是,for循环可以和else一起使用:

In [64]: for n in range(2, 10):
…: for x in range(2, n):
…: if n % x == 0:
…: print(n, ‘equals’, x, ‘*’, n//x)
…: break
…: else:
…: print(n, ‘is a prime number’)
…:
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3

循环中的else语句,会在for循环执行完毕,之后执行。如果我们使用break对for循环进行了中断,那么else语句将不会被执行。

Continue
continue用来跳过此次循环中的后面部分,继续执行下一次循环。

还是刚才的例子,我们使用continue进行改装:

In [68]: for n in range(2, 10):
…: for x in range(2, n):
…: if n % x == 0:
…: print(n, ‘equals’, x, ‘*’, n//x)
…: continue
…: else:
…: print(n, ‘is a prime number’)
…:
2 is a prime number
3 is a prime number
4 equals 2 * 2
4 is a prime number
5 is a prime number
6 equals 2 * 3
6 equals 3 * 2
6 is a prime number
7 is a prime number
8 equals 2 * 4
8 equals 4 * 2
8 is a prime number
9 equals 3 * 3
9 is a prime number

可以看到,在continue中,else语句会一直执行。

pass
pass表示的是什么都不做。是一个空的执行。

通常我们使用pass作为函数或条件子语句的占位符,表示具体的内容可以在未来进行填充。

可以在while中使用pass:

>>> while True:
… pass # Busy-wait for keyboard interrupt (Ctrl+C)

可以在类中使用pass:

>>> class MyEmptyClass:
… pass

可以在函数中使用pass:

>>> def initlog(*args):
… pass # Remember to implement this!

基于 Windows Server 2019 混合 Docker for windows 搭建 Nextcloud 简易攻略

环境:
物理主机系统:Windows server 2019 Datecenter (v1809, 17763.805)
Docker:Docker for windows 2.1.0.4 (Engine: 19.03.4, Compose: 1.24.1)
MySQL:MySQL for win64 8.0.18 Community Server
Nginx:Nginx for windows 1.16.1
Nextcloud:17.0.0 (hub.docker.com/_/nextcloud, nextcloud:latest, nextcloud:apache, OS:Linux/amd64)
可选附加:
Onlyoffice-document-server: https://hub.docker.com/r/onlyoffice/documentserver, tag:latest
redis: https://hub.docker.com/_/redis, tag:latest
总之除了 Nextcloud,附加的 onlyoffice-document-server 和 redis 之外,其余均为基于 windows 的软件

Nextcloud 镜像的选择:在官方 Docker 页面中主要版本有默认的 Apache 版和采用容器化 Nginx 的 FPM 版,在我个人实际搭建过程中 FPM 版的 Nginx 和宿主机 windows 之间隔着一层 NAT,配置调试起来显得十分麻烦,故选择运行起来更简单的 Apache 版

Docker for windows 安装是全自动创建 Docker Host 的 Hyper-V 虚拟机,网络使用 NAT 转发,Host IP 为 10.75.0.1,Container IP 为 10.0.75.0

MySQL Community 创建好供 Nextcloud 使用的 utf8mb4 编码的数据库(database),并设置好相关的用户名和密码,也可以直接使用默认的 root 账户,记得要修改密码

NextCloud 和 Nginx 的搭建后续重点讲述

重点讲述:
Nextcloud 容器:
这个其实百度和谷歌上有一大批的教程,只是个人在实际环境运行中出现了各种各样的小细节问题,还有更多的是这些教程大多数都过时了,当然接下来的所有讲述都是仅供参考,毕竟每个人的运行环境都不同

Compose 文本内包含了 redis 缓存容器和 onlyoffice-document-server 文档服务器容器配置,觉得有用请自取

我个人将一些比较重要的文件和 log 通过 volume 挂载到物理系统 windows server 的 D 盘中,Nextcloud 则是直接将整个 PHP 程序和数据文件夹 /var/www/html 转移到 D:/Docker/nextcloud 中,方便以后直接使用 windows 管理文档

nextcloud 容器用的 “wyxls/nextcloud:full” 镜像是我自建的,Nextcloud 的官方镜像默认不带 smbclient 和 crontab,会影响到外部存储挂载 APP 使用 (因为我主要 windows 的 smb 共享),于是我根据官方提供的 Dockerfile 自建了镜像并上传到 docker hub,不需要的话可以改成 nextcloud 官方的 image ( https://hub.docker.com/_/nextcloud)

Dockerfile example:( https://github.com/nextcloud/docker/blob/master/.examples/dockerfiles/full/apache/Dockerfile)

version: ‘3’
#初始化网络模块,为了让 Nextcloud 和 onlyoffice+redis 协作
networks:
nextcloud:
#services 以下都是容器
services:
#redis 容器,暴露 6379 端口供其他容器使用
redis:
image: redis
container_name: redis
hostname: redis
restart: always
networks:
– nextcloud
expose:
– 6379
#nextcloud 容器,宿主机 10000 端口转发 80 端口访问
nextcloud:
image: wyxls/nextcloud:full
container_name: nextcloud
restart: always
depends_on:
– redis
environment:
– UID=1000
– GID=1000
– UPLOAD_MAX_SIZE=5G
– APC_SHM_SIZE=128M
– OPCACHE_MEM_SIZE=128
– CRON_PERIOD=15m
– TZ=Aisa/Shanghai
– NEXTCLOUD_TABLE_PREFIX=oc_
volumes:
– D:/Docker/nextcloud:/var/www/html
ports:
– 10000:80
networks:
– nextcloud
#onlyoffice 容器,宿主机 10005 端口转发 443 端口访问,在 nextcloud 的 onlyoffice 设置里必须以 https+宿主端口访问
onlyoffice:
container_name: onlyoffice
image: onlyoffice/documentserver:latest
stdin_open: true
tty: true
restart: always
depends_on:
– nextcloud
volumes:
– D:/Docker/onlyoffice/document_data:/var/www/onlyoffice/Data
– D:/Docker/onlyoffice/document_log:/var/log/onlyoffice
– D:/Docker/onlyoffice/document_fonts:/usr/share/fonts/truetype/custom
– D:/Docker/onlyoffice/document_forgotten:/var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten
ports:
– 10005:443
networks:
– nextcloud
在 Docker 容器中运行的 Nextcloud 默认以 root 权限运行所有程序,所以访问时会提示设置权限 chmod 0770,但在我个人实践中无论是 chown 还是 chmod 都无法解决这个问题,后来还是强行忽略文件权限检查

在 /var/www/html/config/config.php 中加入以下一行:

‘check_data_directory_permissions’ => false, #检查数据目录权限
此外别忘了还要添加 Trusted_Domains,不然 Nextcloud 的 Web 端无法访问:

‘trusted_domains’ =>
array (
0 => ‘example.com’,
1 -> ‘localhost’,
),
Nginx:
由于 Docker for windows 是基于 Hyper-V 虚拟机模拟出的 Linux/amd64 系统,相当于物理 windows——Hyper-V 虚拟机( Docker Host 宿主机)——Docker Container (容器)两层 NAT 网络,所以需要使用 Nginx 当中间人进行反向代理,下面是我个人配置的 conf,仅供参考

因为我个人的 Windows Server 内网可以直接通过 SMB 访问管理文件,而 Nextcloud 只进行外网访问,所以我只做了 HTTPS 监听+反向代理,有内网 HTTP 访问需求的可以将 SSL 相关部分注释掉

原本在反向代理 proxy_pass 段有 connect, read, send 等 timeout 限制,但后来发现添加后网页访问和 windows 客户端同步变得异常缓慢,而且频繁报错,故删除

server {
listen 10002 ssl; #Nginx 监听端口
server_name example.com localhost 192.168.x.x; #域名, IP, 本地地址都可以填写
root D:/nextcloud; #nextcloud 目录
index index.php;

ssl_certificate D:/SSL-Certificates/fullchain.cer;
ssl_certificate_key D:/SSL-Certificates/private.key;
ssl_protocols SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;

#以下部分为隐藏 header, 为了解决 nextcloud 自检问题
proxy_hide_header Strict-Transport-Security;
proxy_hide_header X-Content-Type-Options;
proxy_hide_header X-Robots-Tag;
proxy_hide_header X-Frame-Options;
proxy_hide_header X-Download-Options;
proxy_hide_header X-Permitted-Cross-Domain-Policies;
proxy_hide_header Referrer-Policy;
proxy_hide_header X-XSS-Protection;

add_header Strict-Transport-Security “max-age=31536000; includeSubDomains; preload” always;
add_header X-Content-Type-Options nosniff;
add_header X-Robots-Tag “none”;
add_header X-Frame-Options “SAMEORIGIN”;
add_header X-Download-Options “noopen”;
add_header X-Permitted-Cross-Domain-Policies “none”;
add_header Referrer-Policy “no-referrer”;
add_header X-XSS-Protection “1; mode=block”;

client_max_body_size 10G;
fastcgi_buffers 64 4K;
fastcgi_hide_header X-Powered-By;

location / {
proxy_pass http://localhost:10000/; #反向代理地址
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location = /.well-known/carddav { #解决自检 carddav 未正常配置解析提示问题
return 301 $scheme://$http_host/remote.php/dav;
}

location = /.well-known/caldav { #解决自检 carddav 未正常配置解析提示问题
return 301 $scheme://$http_host/remote.php/dav;
}

location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}

location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
deny all;
}

location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
deny all;
}

}
在初步搭好 Nextcloud 后实际使用中经常出现访问超时,原因是 Nextcloud 在反向代理中可能会无法侦测正确的协议,需要强行覆写( Nextcloud 默认 latest 镜像用 Apache 作为 Web server 监听 HTTP 80 端口)

‘overwriteprotocol’ => ‘https’,
额外部分:
Onlyoffice-document-server:
Nextcloud 官方提供连接 onlyoffice 服务的 APP,与 onlyoffice 对接后能实现 Nextcloud 内通过 Web 访问直接打开并编辑 office 相关文档 (pptx, xlsx, docs 等),通过 Docker 可以一键配置

version: ‘3’
services:
onlyoffice:
container_name: onlyoffice
image: onlyoffice/documentserver:latest
stdin_open: true
tty: true
restart: always
depends_on:
– nextcloud
volumes:
– D:/Docker/onlyoffice/document_data:/var/www/onlyoffice/Data
– D:/Docker/onlyoffice/document_log:/var/log/onlyoffice
– D:/Docker/onlyoffice/document_fonts:/usr/share/fonts/truetype/custom
– D:/Docker/onlyoffice/document_forgotten:/var/lib/onlyoffice/documentserver/App_Data/cache/files/forgotten
ports:
– 10005:443
networks:
– nextcloud
证书安装:在 /var/www/onlyoffice/Data 中建立”certs”文件夹并将 SSL 证书及私钥以”onlyoffice.crt”和”onlyoffice.key”保存,或者直接在 yml 中 environment 环境参数添加,在 Docker-Settings-Shared Drives 设置共享后可以直接使用 windows 物理路径指定,比如:D:\SSL-certificates\onlyoffice.crt

environment:
– SSL_CERTIFICATE_PATH=证书路径
– SSL_KEY_PATH=私钥路径
通过访问 https://example.com:10005 可以查看 Document Server 运行状况,显示 Document Server is running 表示成功

*后在 Nextcloud 内设置 Document Editing Service address 为 https://example.com:10005,如果页面下方出现 settings 一类选项则表示已成功连接

Redis:
Nextcloud 官方推荐使用 Redis 缓存 Nextcloud,我自己也不太懂原理,但官方既然推荐了就一起部署上啦

version: ‘3’
services:
redis:
image: redis
container_name: redis
hostname: redis
restart: always
networks:
– nextcloud
expose:
– 6379
记得要在 Nextcloud 对应的 config/config.php 中添加相关内容

‘memcache.local’ => ‘\OC\Memcache\APCu’, #redis
‘memcache.distributed’ => ‘\OC\Memcache\Redis’, #redis
‘memcache.locking’ => ‘\OC\Memcache\Redis’, #redis
‘redis’ => array( #redis
‘host’ => ‘redis’, #如果 redis 部署在物理机上填 localhost,这里由于 redis 和 nextcloud 在同一网络 nextcloud 内,所以可用 redis 代替
‘port’ => 6379,
),
结语:
onlyoffice 目前我个人测试只能在 Docker 内部 Nextcloud 使用,详细原因猜测是 onlyoffice 内置的 Nginx 没正确配置监听或允许外部网络域名访问(反正我软路由的另一个 Nextcloud 对接时显示 Connetion refused )

我凭借着记忆将大致的搭建过程写了出来,难免会有所纰漏,烦请各位朋友查漏指正,有什么问题可以回复交流

此外如果对过程中任何一部分有修正改进的建议,请务必告诉我,我对 Nginx、PHP、MySQL 参数调优真的是一窍不通

牢骚话:

有人可能会问为什么不干脆用 Linux 物理系统来搭,没辙啊,老爸只会用 windows,老妈想着吃饭时间连上去看 iqiyi 的电视剧,家里其他人又想摆一台公用的共享 NAS,我自己对 centOS 又不是特别熟悉,*后翻了一大堆的论坛帖子、网站文章自己摸索,目前也就只能这样先用着了

其实*关键是没钱买群晖,而且家里人的要求比较杂,群晖不能很好地满足,于是这份攻略就诞生了

曾经想过 ESXi 6.7 组建 FreeNAS + centOS + Docker (Nextcloud)+ Windows 7 的大虚拟机,把路由 LEDE 也虚拟化,从此就可以把那台软路由也扔掉,但后来发现搞不定 N 卡直通后给 Windows,重启虚拟机就带着 ESXi 一起死机的问题。据谷歌搜索说是因为 ESXi 6.7 在显卡*次直通给虚拟机后关机时没能正常 reset 显卡状态,导致第二次虚拟机启动时显卡处于正在使用状态而带着宿主机一起 Boom,折腾了两天还是解决不了,随后我就放弃并滚回去用 windows 了

Android Fragment 真正的完全解析(下)

上篇博客中已经介绍了Fragment产生原因,以及一些基本的用法和各种API,如果你还不了解,请看:Android Fragment 真正的完全解析(上)。

本篇将介绍上篇博客提到的:如何管理Fragment回退栈,Fragment如何与Activity交互,Fragment与Activity交互的*佳实践,没有视图的Fragment的用处,使用Fragment创建对话框,如何与ActionBar,MenuItem集成等~~

1、管理Fragment回退栈
类似与Android系统为Activity维护一个任务栈,我们也可以通过Activity维护一个回退栈来保存每次Fragment事务发生的变化。如果你将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次的保存的Fragment。一旦Fragment完全从后退栈中弹出,用户再次点击后退键,则退出当前Activity。

看这样一个效果图:

%title插图%num %title插图%num

点击*个按钮,切换到第二个界面,点击第二个按钮,切换到第三个界面,然后点击Back键依次回退。这像不像初学Android时的Activity跳转,当然了,这里肯定不是,不然我就跪了。这里是Fragment实现的,用户点击Back,实际是Fragment回退栈不断的弹栈。

如何添加一个Fragment事务到回退栈:

FragmentTransaction.addToBackStack(String)

下面讲解代码:很明显一共是3个Fragment和一个Activity.

先看Activity的布局文件:

<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent” >

<FrameLayout
android:id=”@+id/id_content”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent” >
</FrameLayout>

</RelativeLayout>
不同的Fragment就在这个FrameLayout中显示。
MainActivity.java

package com.zhy.zhy_fragments;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Window;

public class MainActivity extends Activity
{

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, new FragmentOne(),”ONE”);
tx.commit();
}

}
很简单,直接将FragmentOne添加到布局文件中的FrameLayout中,注意这里并没有调用FragmentTransaction.addToBackStack(String),因为我不喜欢在当前显示时,点击Back键出现白板。而是正确的相应Back键,即退出我们的Activity.
下面是FragmentOne

package com.zhy.zhy_fragments;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class FragmentOne extends Fragment implements OnClickListener
{

private Button mBtn;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_one, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_one_btn);
mBtn.setOnClickListener(this);
return view;
}

@Override
public void onClick(View v)
{
FragmentTwo fTwo = new FragmentTwo();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.replace(R.id.id_content, fTwo, “TWO”);
tx.addToBackStack(null);
tx.commit();

}

}

我们在点击FragmentOne中的按钮时,使用了replace方法,如果你看了前一篇博客,一定记得replace是remove和add的合体,并且如果不添加事务到回退栈,前一个Fragment实例会被销毁。这里很明显,我们调用tx.addToBackStack(null);将当前的事务添加到了回退栈,所以FragmentOne实例不会被销毁,但是视图层次依然会被销毁,即会调用onDestoryView和onCreateView,证据就是:仔细看上面的效果图,我们在跳转前在文本框输入的内容,在用户Back得到*个界面的时候不见了。
接下来FragmentTwo

package com.zhy.zhy_fragments;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class FragmentTwo extends Fragment implements OnClickListener
{

private Button mBtn ;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_two, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_two_btn);
mBtn.setOnClickListener(this);
return view ;
}
@Override
public void onClick(View v)
{
FragmentThree fThree = new FragmentThree();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.hide(this);
tx.add(R.id.id_content , fThree, “THREE”);
// tx.replace(R.id.id_content, fThree, “THREE”);
tx.addToBackStack(null);
tx.commit();
}

}

这里点击时,我们没有使用replace,而是先隐藏了当前的Fragment,然后添加了FragmentThree的实例,*后将事务添加到回退栈。这样做的目的是为了给大家提供一种方案:如果不希望视图重绘该怎么做,请再次仔细看效果图,我们在FragmentTwo的EditText填写的内容,用户Back回来时,数据还在~~~
*后FragmentThree就是简单的Toast了:

package com.zhy.zhy_fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;

public class FragmentThree extends Fragment implements OnClickListener
{

private Button mBtn;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_three, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_three_btn);
mBtn.setOnClickListener(this);
return view;
}

@Override
public void onClick(View v)
{
Toast.makeText(getActivity(), ” i am a btn in Fragment three”,
Toast.LENGTH_SHORT).show();
}

}

好了,经过上面的介绍,应该已经知道Fragment回退栈是怎么一回事了,以及hide,replace等各自的应用的场景。
这里*其注意一点:上面的整体代码不具有任何参考价值,纯粹为了显示回退栈,在后面讲解了Fragment与Activity通信以后,会重构上面的代码!

2、Fragment与Activity通信
因为所有的Fragment都是依附于Activity的,所以通信起来并不复杂,大概归纳为:

a、如果你Activity中包含自己管理的Fragment的引用,可以通过引用直接访问所有的Fragment的public方法

b、如果Activity中未保存任何Fragment的引用,那么没关系,每个Fragment都有一个唯一的TAG或者ID,可以通过getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实例,然后进行操作。

c、在Fragment中可以通过getActivity得到当前绑定的Activity的实例,然后进行操作。

注:如果在Fragment中需要Context,可以通过调用getActivity(),如果该Context需要在Activity被销毁后还存在,则使用getActivity().getApplicationContext()。

3、Fragment与Activity通信的*佳实践
因为要考虑Fragment的重复使用,所以必须降低Fragment与Activity的耦合,而且Fragment更不应该直接操作别的Fragment,毕竟Fragment操作应该由它的管理者Activity来决定。

下面我通过两种方式的代码,分别重构,FragmentOne和FragmentTwo的点击事件,以及Activity对点击事件的响应:

首先看FragmentOne

package com.zhy.zhy_fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class FragmentOne extends Fragment implements OnClickListener
{
private Button mBtn;

/**
* 设置按钮点击的回调
* @author zhy
*
*/
public interface FOneBtnClickListener
{
void onFOneBtnClick();
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_one, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_one_btn);
mBtn.setOnClickListener(this);
return view;
}

/**
* 交给宿主Activity处理,如果它希望处理
*/
@Override
public void onClick(View v)
{
if (getActivity() instanceof FOneBtnClickListener)
{
((FOneBtnClickListener) getActivity()).onFOneBtnClick();
}
}

}

可以看到现在的FragmentOne不和任何Activity耦合,任何Activity都可以使用;并且我们声明了一个接口,来回调其点击事件,想要管理其点击事件的Activity实现此接口就即可。可以看到我们在onClick中首先判断了当前绑定的Activity是否实现了该接口,如果实现了则调用。
再看FragmentTwo

package com.zhy.zhy_fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;

public class FragmentTwo extends Fragment implements OnClickListener
{

private Button mBtn ;

private FTwoBtnClickListener fTwoBtnClickListener ;

public interface FTwoBtnClickListener
{
void onFTwoBtnClick();
}
//设置回调接口
public void setfTwoBtnClickListener(FTwoBtnClickListener fTwoBtnClickListener)
{
this.fTwoBtnClickListener = fTwoBtnClickListener;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_two, container, false);
mBtn = (Button) view.findViewById(R.id.id_fragment_two_btn);
mBtn.setOnClickListener(this);
return view ;
}
@Override
public void onClick(View v)
{
if(fTwoBtnClickListener != null)
{
fTwoBtnClickListener.onFTwoBtnClick();
}
}

}

与FragmentOne*其类似,但是我们提供了setListener这样的方法,意味着Activity不仅需要实现该接口,还必须显示调用mFTwo.setfTwoBtnClickListener(this)。
*后看Activity :

package com.zhy.zhy_fragments;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Window;

import com.zhy.zhy_fragments.FragmentOne.FOneBtnClickListener;
import com.zhy.zhy_fragments.FragmentTwo.FTwoBtnClickListener;

public class MainActivity extends Activity implements FOneBtnClickListener,
FTwoBtnClickListener
{

private FragmentOne mFOne;
private FragmentTwo mFTwo;
private FragmentThree mFThree;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, “ONE”);
tx.commit();
}

/**
* FragmentOne 按钮点击时的回调
*/
@Override
public void onFOneBtnClick()
{

if (mFTwo == null)
{
mFTwo = new FragmentTwo();
mFTwo.setfTwoBtnClickListener(this);
}
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.replace(R.id.id_content, mFTwo, “TWO”);
tx.addToBackStack(null);
tx.commit();
}

/**
* FragmentTwo 按钮点击时的回调
*/
@Override
public void onFTwoBtnClick()
{
if (mFThree == null)
{
mFThree = new FragmentThree();

}
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.hide(mFTwo);
tx.add(R.id.id_content, mFThree, “THREE”);
// tx.replace(R.id.id_content, fThree, “THREE”);
tx.addToBackStack(null);
tx.commit();
}

}

代码重构结束,与开始的效果一模一样。上面两种通信方式都是值得推荐的,随便选择一种自己喜欢的。这里再提一下:虽然Fragment和Activity可以通过getActivity与findFragmentByTag或者findFragmentById,进行任何操作,甚至在Fragment里面操作另外的Fragment,但是没有特殊理由是*对不提倡的。Activity担任的是Fragment间类似总线一样的角色,应当由它决定Fragment如何操作。另外虽然Fragment不能响应Intent打开,但是Activity可以,Activity可以接收Intent,然后根据参数判断显示哪个Fragment。
4、如何处理运行时配置发生变化
运行时配置发生变化,*常见的就是屏幕发生旋转,如果你不知道如何处理屏幕变化可以参考:Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的*佳方案

这里提一下:很多人觉得强制设置屏幕的方向就可以了,但是有一点,当你的应用被至于后台(例如用户点击了home),长时间没有返回的时候,你的应用也会被重新启动。比如上例:如果你把上面的例子你至于FragmentThree界面,然后处于后台状态,长时间后你会发现当你再次通过home打开时,上面FragmentThree与FragmentOne叠加在一起,这就是因为你的Activity重新启动,在原来的FragmentThree上又绘制了一个FragmentOne。

好了,下面看一段代码:

Activity:

package com.zhy.zhy_fragments;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Window;

public class MainActivity extends Activity

{
private FragmentOne mFOne;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, “ONE”);
tx.commit();

}

}

Fragment
package com.zhy.zhy_fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class FragmentOne extends Fragment
{
private static final String TAG = “FragmentOne”;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
Log.e(TAG, “onCreateView”);
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}

@Override
public void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

Log.e(TAG, “onCreate”);
}

@Override
public void onDestroyView()
{
// TODO Auto-generated method stub
super.onDestroyView();
Log.e(TAG, “onDestroyView”);
}

@Override
public void onDestroy()
{
// TODO Auto-generated method stub
super.onDestroy();
Log.e(TAG, “onDestroy”);
}

}

很简单的代码,当你运行之后,不断的旋转屏幕,你会发现每旋转一次屏幕,屏幕上就多了一个FragmentOne的实例,并且后台log会打印出许多套生命周期的回调。
类似:

07-20 08:18:46.651: E/FragmentOne(1633): onCreate
07-20 08:18:46.651: E/FragmentOne(1633): onCreate
07-20 08:18:46.651: E/FragmentOne(1633): onCreate
07-20 08:18:46.681: E/FragmentOne(1633): onCreateView
07-20 08:18:46.831: E/FragmentOne(1633): onCreateView
07-20 08:18:46.891: E/FragmentOne(1633): onCreateView

这是为什么呢,因为当屏幕发生旋转,Activity发生重新启动,默认的Activity中的Fragment也会跟着Activity重新创建;这样造成当旋转的时候,本身存在的Fragment会重新启动,然后当执行Activity的onCreate时,又会再次实例化一个新的Fragment,这就是出现的原因。
那么如何解决呢:

其实通过检查onCreate的参数Bundle savedInstanceState就可以判断,当前是否发生Activity的重新创建:

默认的savedInstanceState会存储一些数据,包括Fragment的实例:通过打印可以看出:

07-20 08:23:12.952: E/FragmentOne(1782): Bundle[{android:fragments=android.app.FragmentManagerState@40d0b7b8, android:viewHierarchyState=Bundle[{android:focusedViewId=2131230721, android:views=android.util.SparseArray@40d0af68}]}]
所以,我们简单改一下代码,只有在savedInstanceState==null时,才进行创建Fragment实例:
package com.zhy.zhy_fragments;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;

public class MainActivity extends Activity

{
private static final String TAG = “FragmentOne”;
private FragmentOne mFOne;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

Log.e(TAG, savedInstanceState+””);

if(savedInstanceState == null)
{
mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, “ONE”);
tx.commit();
}

}

}

现在无论进行多次旋转都只会有一个Fragment实例在Activity中。
现在还存在一个问题,就是重新绘制时,Fragment发生重建,原本的数据如何保持?

其实和Activity类似,Fragment也有onSaveInstanceState的方法,在此方法中进行保存数据,然后在onCreate或者onCreateView或者onActivityCreated进行恢复都可以。

由于篇幅原因,就不贴测试代码了。

5、Fragmeny与ActionBar和MenuItem集成
Fragment可以添加自己的MenuItem到Activity的ActionBar或者可选菜单中。

a、在Fragment的onCreate中调用 setHasOptionsMenu(true);

b、然后在Fragment子类中实现onCreateOptionsMenu

c、如果希望在Fragment中处理MenuItem的点击,也可以实现onOptionsItemSelected;当然了Activity也可以直接处理该MenuItem的点击事件。

代码:

Fragment

package com.zhy.zhy_fragments;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class FragmentOne extends Fragment
{

@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
inflater.inflate(R.menu.fragment_menu, menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.id_menu_fra_test:
Toast.makeText(getActivity(), “FragmentMenuItem1”, Toast.LENGTH_SHORT).show();
break;
}
return true;
}

}

Activity
package com.zhy.zhy_fragments;

import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Window;
import android.widget.Toast;

public class MainActivity extends Activity

{
private static final String TAG = “FragmentOne”;
private FragmentOne mFOne;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);

Log.e(TAG, savedInstanceState + “”);

if (savedInstanceState == null)
{
mFOne = new FragmentOne();
FragmentManager fm = getFragmentManager();
FragmentTransaction tx = fm.beginTransaction();
tx.add(R.id.id_content, mFOne, “ONE”);
tx.commit();
}

}

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.action_settings:
Toast.makeText(this, “setting”, Toast.LENGTH_SHORT).show();
return true;
default:
//如果希望Fragment自己处理MenuItem点击事件,一定不要忘了调用super.xxx
return super.onOptionsItemSelected(item);
}
}

}

效果图:

%title插图%num

%title插图%num

好了,可以很好的看到,Fragment可以添加MenuItem,也可以自己处理点击~~~

6、没有布局的Fragment的作用
没有布局文件Fragment实际上是为了保存,当Activity重启时,保存大量数据准备的

请参考博客:Android 屏幕旋转 处理 AsyncTask 和 ProgressDialog 的*佳方案

7、使用Fragment创建对话框
这是Google推荐的方式,我也单独写过博客介绍,请参考:Android 官方推荐 : DialogFragment 创建对话框

好了,终于把Fragment相关的联系到一起了,上述基本包含了Fragment所有的用法~~~相信大家如果能够看完,一定有不少的收获~~~

有任何问题,欢迎留言~~~

两篇结束,相信你对Fragment已经有了一定的了解,那么在项目中的*佳实践是什么呢?请移步:Android Fragment 你应该知道的一切

KMS服务器关于Vol Windows/Office命令

可用的KMS服务器地址:

zh.us.to 有效

kms.03k.org 有效

kms.chinancce.com 有效

kms.shuax.com 有效

kms.dwhd.org 有效

kms.luody.info 有效

kms.digiboy.ir 有效

kms.lotro.cc 有效

www.zgbs.cc 有效

cy2617.jios.org 有效

 

假如你的服务器IP是1.1.1.1

Windows用下面两条命令:(需要cmd在管理员权限下执行)

slmgr -skms 1.1.1.1

slmgr -ato
查看Windows状态用下面命令(KMS连接周期,剩余时间等):

slmgr.vbs /dlv
Office用下面这条命令:(需要cmd在管理员权限下执行)

cscript “E:\Microsoft Office\Office16\OSPP.VBS” /sethst:1.1.1.1
查看Office状态用下面这条命令:(需要cmd在管理员权限下执行)

cscript “E:\Microsoft Office\Office16\OSPP.VBS” /dstatus
其中E:\Microsoft Office\Office16   是Office2016中OSPP.VBS 所在的目录,Office16代表Office2016;Office15达标Office2013;Office14代表Office2010;

tidb分布式数据库是mysql_常见问题-分布式数据库 TiDB-帮助文档-京东智联云

常见问题

1. 分布式数据库 TiDB 是基于 MySQL 开发的吗?

不是,但是分布式数据库 TiDB 支持 MySQL 语法和协议。

2. 用起来简单吗?

是的,分布式数据库 TiDB 用起来很简单。启动整套服务后,就可以将 分布式数据库 TiDB 当做一个普通的 MySQL Server 来用,您可以将 分布式数据库 TiDB 用在任何以 MySQL 作为后台存储服务的应用中,基本上不需要修改应用代码,并且兼容大部分 MySQL 管理工具。

3. 适用的场景?

原业务的 MySQL 的业务遇到单机容量或者性能瓶颈时,可以考虑使用 分布式数据库 TiDB 无缝替换 MySQL。

4. 如何将运行在 MySQL 上的应用迁移到 分布式数据库 TiDB 上?

分布式数据库 TiDB 大多数 MySQL 语法,一般不需要修改代码,可以用工具 Checker 检查 MySQL 中的 Schema 是否兼容。

5. TiDB 具备高可用的特性吗?

TiDB 具备高可用特性,TiDB、TiKV、PD 这三个组件都能容忍部分实例失效,不影响整个集群的可用性。

6. TiDB 数据是强一致的吗?

TiDB 使用 Raft 在多个副本之间做数据同步,从而保证数据的强一致,单个副本失效时,不影响数据的可靠性。

7. TiDB 用户名长度限制?

在 TiDB 中用户名*长为 32 字符。

8. 一个事务中的语句数量*大是多少?

一个事务中的语句数量,默认限制*大为 5000 条。

9. 如何通过扩展 分布式数据库 TiDB 提高性能?

随着业务不断增长时,数据库可能会面临三方面瓶颈: – *是存储资源不够,也就是磁盘空间不够; – 第二是计算资源不够用,如 CPU 占用较高; – 第三是吞吐跟不上;

这时可以对数据库集群做水平扩展。 – 如果是存储资源不够,可以通过添加 TiKV Server 节点来解决。新节点启动后,PD 会自动将其他节点的部分数据迁移过去,无需人工介入。 – 如果是计算资源不够,可以查看 TiDB 节点 和 TiKV 节点的 CPU 消耗情况,再考虑添加 TiDB 节点或者是 TiKV 节点来解决。 – 如果是吞吐跟不上,一般可以考虑同时增加 TiDB 节点 和 TiKV 节点。
————————————————
版权声明:本文为CSDN博主「冰浠」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_30980025/article/details/114471493

Python基础之:函数

Python基础之:函数

文章目录
简介
内置函数
自定义函数
参数的默认值
关键字参数
特殊参数
参数解包
Lambda
函数标注
简介
函数是结构化编程的基础,也是代码复用的基石。Python中通过def来自定义函数。本文将会深入探索Python中函数的秘密。

内置函数
除了用户的自定义函数之外,Python内置了一些非常有用的函数:

内置函数
abs() delattr() hash() memoryview() set()
all() dict() help() min() setattr()
any() dir() hex() next() slice()
ascii() divmod() id() object() sorted()
bin() enumerate() input() oct() staticmethod()
bool() eval() int() open() str()
breakpoint() exec() isinstance() ord() sum()
bytearray() filter() issubclass() pow() super()
bytes() float() iter() print() tuple()
callable() format() len() property() type()
chr() frozenset() list() range() vars()
classmethod() getattr() locals() repr() zip()
compile() globals() map() reversed() __import__()
complex() hasattr() max() round()
自定义函数
Python中使用def来定义函数,并使用return来返回特定的值。

看一个简单的函数的例子:

def my_function(x, y, z):
if z > 1:
return z * (x + y)
else:
return z / (x + y)

把我们之前讲的斐波拉赫数列的例子重新用函数来定义,可以这样写:

def fib(n):
a, b = 0, 1
while a < n:
print(a, end=’ ‘)
a, b = b, a+b
print()

# 调用函数
fib(1000)

函数的内容需要使用空格或者tab来进行缩进。

参数的默认值
在Python中,我们可以给参数设置默认值,这样如果在函数调用的过程中没有传递参数的时候,就会使用默认值作为参数。

在我们之前定义的函数my_function中,我们可以给z设置一个默认值:

def my_function(x, y, z=10):
if z > 1:
return z * (x + y)
else:
return z / (x + y)

这样我们在调用my_function可以只用传递两个参数,*后的z可以使用默认的参数值。

注意,默认值只会执行一次,如果你传入的参数是可变对象(列表,字典和类实例)的话,我们需要注意这个问题:

def f(a, L=[]):
L.append(a)
return L

print(f(1))
print(f(2))
print(f(3))

# 输出
[1]
[1, 2]
[1, 2, 3]

如果不想在后面的调用中共享默认值,那么可以把默认值的赋值放到函数体内部:

def f(a, L=None):
if L is None:
L = []
L.append(a)
return L

关键字参数
我们可以使用key=value的方式对函数进行调用。

还是前面的函数:

def my_function(x, y, z=10):
if z > 1:
return z * (x + y)
else:
return z / (x + y)

我们可以这样调用:

my_function(1,y=3,z=5)
my_function(1,y=3)

但是不能这样用:

my_function(y=3,1)

关键字的参数必须要放在非关键词参数的后面。也不能对参数进行多次赋值:

>>> def function(a):
… pass

>>> function(0, a=0)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: function() got multiple values for keyword argument ‘a’

通过上面的讨论我们可以看出,Python函数中的参数有两种,一种是带默认值的参数,一种是不带默认值的参数。

注意,不带默认值的参数一定要在带默认值的参数之前 。

看一个错误的例子:

In [69]: def fa(a=100,b,c=200):
…: pass
File “<ipython-input-69-d5678b64f352>”, line 1
def fa(a=100,b,c=200):
^
SyntaxError: non-default argument follows default argument

而向函数传递参数也有两种方式,一种是不带关键字的传递,一种是带关键字的传递。

注意,非关键词参数的传递一定要在关键词参数传递之前。

举个错误的例子:

In [70]: def fa(a,b=100,c=200):
…: pass
…:

In [71]: fa(a=100,30)
File “<ipython-input-71-5a229b8e420e>”, line 1
fa(a=100,30)
^
SyntaxError: positional argument follows keyword argument

那么问题来了,如果有多个关键词参数和多个非关键词参数,有没有简便的方法来定义这样的函数呢?

有的,那就是 *arguments 和 **keywords

*arguments用来接收所有多余的非关键词参数。而**keywords用来接收所有额外的关键词参数。

注意,*arguments一定要出现在 **keywords 的前面。

举个例子:

def cheeseshop(kind, *arguments, **keywords):
print(“– Do you have any”, kind, “?”)
print(“– I’m sorry, we’re all out of”, kind)
for arg in arguments:
print(arg)
print(“-” * 40)
for kw in keywords:
print(kw, “:”, keywords[kw])

我们可以这样调用:

cheeseshop(“Limburger”, “It’s very runny, sir.”,
“It’s really very, VERY runny, sir.”,
shopkeeper=”Michael Palin”,
client=”John Cleese”,
sketch=”Cheese Shop Sketch”)

将会得到下面的结果:

— Do you have any Limburger ?
— I’m sorry, we’re all out of Limburger
It’s very runny, sir.
It’s really very, VERY runny, sir.
—————————————-
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch

特殊参数
函数可以按位置传参,可以按照关键词传参,也可以混合传参。

在某些情况下,我们可能需要限制传参的类型,比如只接收按位置传递,只接收按关键词传递,或者只接受混合传递。

看下特殊参数的定义:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
———– ———- ———-
| | |
| 按位置或者关键词 |
| – 只允许按关键词传递
— 只允许按位置传递

注意,参数之间是以 / 和 * 来进行区分的。

我们举个例子:

>>> def standard_arg(arg):
… print(arg)

>>> def pos_only_arg(arg, /):
… print(arg)

>>> def kwd_only_arg(*, arg):
… print(arg)

>>> def combined_example(pos_only, /, standard, *, kwd_only):
… print(pos_only, standard, kwd_only)

上面定义了4种传参方式的函数。

*个函数就是标准形式,可以按位置传递,也可以按关键词传递。

第二个函数只允许按照位置传递。

第三个函数只允许按照关键词来传递。

第四个函数是混合模式。

参数解包
有时候我们需要将列表或者字典的值转换为函数的参数。那么就需要用到参数解包的功能。

* 操作符 可以用来解包列表和元组。

>>> list(range(3, 6)) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args)) # call with arguments unpacked from a list
[3, 4, 5]

** 操作符 可以用来解包字典。

>>> def parrot(voltage, state=’a stiff’, action=’voom’):
… print(“– This parrot wouldn’t”, action, end=’ ‘)
… print(“if you put”, voltage, “volts through it.”, end=’ ‘)
… print(“E’s”, state, “!”)

>>> d = {“voltage”: “four million”, “state”: “bleedin’ demised”, “action”: “VOOM”}
>>> parrot(**d)

Lambda
熟悉java的朋友可能知道,在JDK8中,Java引入了Lambda表达式。同样的Python中也有Lambda。

你可以将Lambda看做是匿名函数。可以在任何需要函数的地方使用Lambda表达式。

看一个Lambda的例子:

>>> def make_incrementor(n):
… return lambda x: x + n

>>> f = make_incrementor(42)
>>> f(0)
42
>>> f(1)

还可以将lambda的返回值作为参数:

>>> pairs = [(1, ‘one’), (2, ‘two’), (3, ‘three’), (4, ‘four’)]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, ‘four’), (1, ‘one’), (3, ‘three’), (2, ‘two’)]

函数标注
之前我们讨论的是简单的自定义函数形式,我们并不知道函数的参数类型和返回值类型,其实函数可以写得更加详细一些,这就要用到函数标注了。

所谓函数标注就是用户自定义函数中的类型的可选元数据信息。

函数标注是以字典的形式存放在 __annotations__ 属性中的。我们在参数的名称后面加上冒号,后面跟一个表达式,那么这个表达式会被求值为标注的值。对于返回值来说,返回值标注的定义是加上一个组合符号 ->,后面跟一个表达式,该标注位于形参列表和表示 def 语句结束的冒号之间。

举个例子:

>>> def f(ham: str, eggs: str = ‘eggs’) -> str:
… print(“Annotations:”, f.__annotations__)
… print(“Arguments:”, ham, eggs)
… return ham + ‘ and ‘ + eggs

>>> f(‘spam’)
Annotations: {‘ham’: <class ‘str’>, ‘return’: <class ‘str’>, ‘eggs’: <class ‘str’>}
Arguments: spam eggs
‘spam and eggs’

其实使用函数标注写出来的程序更加清晰,可读性更高。

阿里云ECS 云服务器和轻量应用服务器 区别

什么是阿里云轻量应用服务器?

轻量应用服务器是面向入门级云计算及简单应用用户,提供基于单台云服务器的域名管理、应用部署、安全和运维管理的一站式综合服务。用户可以选择精品应用镜像(比如wordpress),并可在控制台实现全方位的服务器、域名、防火墙、安全防控、监控等管理和操作。轻量应用服务器 (Simple Application Server),是可快速搭建且易于管理的轻量级云服务器。

如下介绍:

%title插图%num

注:学生身份购买,会便宜一些。

阿里云轻量应用服务器的优点是什么?
1.易用易上手。

产品针对单机用户的购买和使用做了操作和使用优化,提供精品镜像、资源套餐、多产品关联(VPC、安全产品、域名管理等)。简单三步就可以轻松开始使用轻量应用服务器

a.选择镜像,并购买(创建)服务器;

b.配置应用:通过查看控制台已经安装好的应用信息,并通过登录服务器查看初始化应用的密码,登录应用后台配置应用;

c.将域名解析到服务器IP。

2.性价比高。

在集合多个必用或常用产品、提供更多基础功能,优化使用体验的同时,并未增加额外费用,且提供了更加优惠的价格,旨在提供更多用户低门槛上云实践机会。

阿里云轻量应用服务器与阿里云ecs云服务器有什么区别?
跟ECS相比,采用同ECS共享版相同的CPU,均采用Intel(R) Xeon(R) CPU E5-2682 v4@ 2.50GHz CPU,但轻量应用服务器将系统盘升级为SSD,虽然容量小了一半,但使用SSD,性能应该是有不错的提升。相同CPU,内存不知道是否相同型号的情况下,单来比较磁盘读写性能,可见速度的提升明显。

介绍
所以就有了轻量应用服务器(轻量应用服务器),基于 ECS 发展出的轻量服务器,完美解决了上述的三个痛点:

轻量应用服务器 是 IaaS 产品但是提供定制化应用镜像且有可视化控制台可以操作,不怕新手不会用。轻量应用服务器 在提供
提供定制化应用镜像的同时,用户依旧可以拥有 root 权限,对系统进行个性化操作
精简了一些 ECS 的功能,比如说安骑士。把安全组的操作也做了适当减法更适合用户操作
不过别看多了轻量两个字性能就会不如 ECS,在 CPU 和 磁盘性能上均没有缩水,后面会有测评。

优点
控制台
轻量应用服务器

那么从控制台的对比上,ECS 是把所有的内容都告诉用户你的地域、操作系统、标签等等,但是新手看了难免一头雾水。而 轻量应用服务器 则做了减法,让控制台变得更加的直观简介,只告诉你重要的信息。

站在新手视角肯定是 轻量应用服务器 更简洁更舒服,站在我的角度么,我配置好服务器基本上很少会来看一下 ECS 的控制台,但一回来肯定是需要一些信息的,那么 ECS 能告诉我越多肯定越好。

应用镜像

应用镜像像 WordPress、phpwind 其实都是基于 LAMP 镜像运行的,而 轻量应用服务器 提供的 LAMP 细节好评就是:php 是通过 php-fpm 方式运行的,而不是 mod_php,而且 MySQL 也是 5.7 版本的不是说万年 5.1 或者 5.5,能支持更多的 PHP 程序。在创建虚拟主机绑定域名商相较于一键包配合图形化控制台的确更加好用。

功能

轻量应用服务器 在功能上肯定是更讨喜的,安装应用镜像基本上能做到开箱即用,三大金刚 Apache Httpd、PHP、MySQL 都会默认安装好,而且添加域名、设置 HTTPS 等操作都是一键式的,*大得降低了 HTTPS 入门门槛,而且 HTTPS 的配置跑分是 A 哟,为了照顾新手不会使用 HSTS 所以没开,不然跑到 A+ 肯定是妥妥的。

ECS 能就只有空白的系统镜像,任何环境都是需要用户自行安装的,这在一定程度上增加了用户使用的学习成本。而 ECS 更多体现的就是专业性了,虽然复杂但是十分强大的安全组、弹性IP、均衡负载等等。

基础运维

比如说 ECS 控制台操作起来也更加的方便,点击一下就能远程连接了,操作的过程中也支持命令的右键复制和粘贴,也大大降低了用户使用终端控制的学习成本,不然还要下个 Putty 或者 Xshell 啥的也是麻烦。 然后默认只支持 密钥 登录 Linux,这个也是好评,不用密码当然更安全。

同样不考虑使用 Putty 或者 Xshell 等 OpenSSH 连接工具的话,ECS控制台的远程终端控制实在是难用,不过借助 DMS 产品倒是能扩展使用的灵活性。

防火墙

轻量的防火墙设置同 ECS 的安全组相比很简单直观更适合新手的使用,没有一些非常复杂的设置,新手看到 udp、tcp 真的是头都大了额,如果新手看教程的话,一般只会说 “记得一定要开启443端口才能使用HTTPS” 这样的话,但是一看到 ECS 又是 TCP 又是 UDP,而且端口还要写成 443/443 的形式,直接就是一个头两个大了。

缺点
无法满足企业特性
轻量应用服务器有轻量两个字,意味着其无法持续进行高负载运行(即 CPU 长时间高负载占用),如果我们要利用 轻量应用服务器 来进行持续的渲染、转码、机器学习等持续高负载操作那么就不可以了,也不支持 Nvme 这样的超高性能的 SSD,这对于读写敏感的操作就不好了。

三大金刚的版本问题
Apache Httpd、PHP、MySQL 是会持续更新的,而且它们也均有爆发过大规模严重漏洞的历史,不过目前还没有看到应用镜像中的三大金刚如何升级版本号的姿势。

像 WordPress 这样的程序完全可以适应高版本的 PHP,使用 PHP7.0 或者 7.1 可以拥有更高的性能还可以降低负载,但是默认只有 php5.6 可以选,既然使用 php-fpm 方式驱动其实完全可以提供多版本 PHP 的选择。

总结
可以说 轻量应用服务器 是专门针对云计算入门新手或者只有轻量计算需求的用户,其对标的产品只会是 ECS 的共享型,当一到要使用 ECS 的企业型来发展性能、功能了,轻量应用服务器 的优势其实也就没有了。

如果你只是轻度使用云计算产品例如搭建一个博客、官网,如果你需要一个更快启动的轻量服务器,如果你需要一个纯粹的虚拟专用机,如果你并没有阿里云内网的需求,那么 轻量应用服务器 *对是你*好的选择。

评测
我们对比的是华东1地域的安装了 CentOS 7.3 系统的 1核心1G内存的 ECS 和 轻量应用服务器 产品。看了评测就可以跟深入的了解,ECS 和 轻量应用服务器 的不同只在于概念而不在于性能。

CPU 性能
根据下面的对比可以发现,轻量应用服务器 的性能和 ECS 并没有差距,大家都是新一代的 Xeon CPU,同样的虚拟化技术。只不过 轻量应用服务器 不可以持续高负载占用。

轻量应用服务器:

System Benchmarks Index Values BASELINE RESULT INDEX
Dhrystone 2 using register variables 116700.0 34281977.0 2937.6
Double-Precision Whetstone 55.0 2962.7 538.7
Execl Throughput 43.0 4860.0 1130.2
File Copy 1024 bufsize 2000 maxblocks 3960.0 1054197.7 2662.1
File Copy 256 bufsize 500 maxblocks 1655.0 283098.8 1710.6
File Copy 4096 bufsize 8000 maxblocks 5800.0 3165160.0 5457.2
Pipe Throughput 12440.0 1734490.3 1394.3
Pipe-based Context Switching 4000.0 375732.0 939.3
Process Creation 126.0 18345.1 1456.0
Shell Scripts (1 concurrent) 42.4 6747.0 1591.3
Shell Scripts (8 concurrent) 6.0 921.5 1535.8
System Call Overhead 15000.0 2939229.7 1959.5
========
System Benchmarks Index Score 1649.5

ECS:

System Benchmarks Index Values BASELINE RESULT INDEX
Dhrystone 2 using register variables 116700.0 34582858.9 2963.4
Double-Precision Whetstone 55.0 2984.8 542.7
Execl Throughput 43.0 5118.8 1190.4
File Copy 1024 bufsize 2000 maxblocks 3960.0 1073823.9 2711.7
File Copy 256 bufsize 500 maxblocks 1655.0 284701.5 1720.3
File Copy 4096 bufsize 8000 maxblocks 5800.0 3213933.6 5541.3
Pipe Throughput 12440.0 1722785.7 1384.9
Pipe-based Context Switching 4000.0 377999.7 945.0
Process Creation 126.0 18704.4 1484.5
Shell Scripts (1 concurrent) 42.4 6852.6 1616.2
Shell Scripts (8 concurrent) 6.0 937.2 1562.0
System Call Overhead 15000.0 2979190.8 1986.1
========
System Benchmarks Index Score 1673.4

磁盘性能
由下面的磁盘跑分也可以看见,轻量应用服务器 的 20G SSD 系统盘 和 ECS 的 20G SSD 云盘的性能都是一致的,都是 1800 的iops,也都是 90M 左右的读写没有差距。

轻量应用服务器:

/dev/vda:
Timing cached reads: 21070 MB in 2.00 seconds = 10549.25 MB/sec
Timing buffered disk reads: 270 MB in 3.01 seconds = 89.76 MB/sec

[root@izbp1auqkyqtj4iozs7athz dev]# fio –bs=4k –ioengine=libaio –iodepth=1 –direct=1 –rw=read –time_based –runtime=600 –refill_buffers –norandommap –randrepeat=0 –group_reporting –name=fio-read –size=10G –filename=/dev/vda
fio-read: (g=0): rw=read, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=1
fio-2.2.8
Starting 1 process
Jobs: 1 (f=1): [R(1)] [100.0% done] [7200KB/0KB/0KB /s] [1800/0/0 iops] [eta 00m:00s]
fio-read: (groupid=0, jobs=1): err= 0: pid=24361: Sun Sep 10 15:04:27 2017
read : io=4206.7MB, bw=7179.3KB/s, iops=1794, runt=600004msec
slat (usec): min=3, max=165, avg= 6.78, stdev= 2.02
clat (usec): min=2, max=84748, avg=548.56, stdev=2727.93
lat (usec): min=131, max=84755, avg=555.59, stdev=2727.93
clat percentiles (usec):
| 1.00th=[ 141], 5.00th=[ 241], 10.00th=[ 302], 20.00th=[ 306],
| 30.00th=[ 314], 40.00th=[ 322], 50.00th=[ 334], 60.00th=[ 350],
| 70.00th=[ 362], 80.00th=[ 382], 90.00th=[ 442], 95.00th=[ 502],
| 99.00th=[ 1012], 99.50th=[23936], 99.90th=[40704], 99.95th=[42752],
| 99.99th=[68096]
bw (KB /s): min= 4624, max= 7784, per=100.00%, avg=7182.85, stdev=181.15
lat (usec) : 4=0.01%, 250=6.25%, 500=88.69%, 750=3.79%, 1000=0.27%
lat (msec) : 2=0.36%, 4=0.06%, 10=0.03%, 20=0.04%, 50=0.48%
lat (msec) : 100=0.04%
cpu : usr=0.50%, sys=1.81%, ctx=1076903, majf=1, minf=33
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=1076894/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
READ: io=4206.7MB, aggrb=7179KB/s, minb=7179KB/s, maxb=7179KB/s, mint=600004msec, maxt=600004msec

Disk stats (read/write):
vda: ios=1078167/690, merge=0/399, ticks=598805/4230, in_queue=602927, util=98.01%

ECS:

/dev/vdb:
Timing cached reads: 19778 MB in 2.00 seconds = 9901.01 MB/sec
Timing buffered disk reads: 270 MB in 3.02 seconds = 89.54 MB/sec

[root@iZbp1258gr0v9v184jdqqkZ dev]# fio –bs=4k –ioengine=libaio –iodepth=1 –direct=1 –rw=read –time_based –runtime=600 –refill_buffers –norandommap –randrepeat=0 –group_reporting –name=fio-read –size=10G –filename=/dev/vdb
fio-read: (g=0): rw=read, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=1
fio-2.2.8
Starting 1 process
Jobs: 1 (f=1): [R(1)] [100.0% done] [6940KB/0KB/0KB /s] [1735/0/0 iops] [eta 00m:00s]
fio-read: (groupid=0, jobs=1): err= 0: pid=9552: Sun Sep 10 15:23:44 2017
read : io=4218.9MB, bw=7200.2KB/s, iops=1800, runt=600001msec
slat (usec): min=3, max=344, avg= 6.97, stdev= 2.32
clat (usec): min=1, max=85711, avg=546.79, stdev=4741.30
lat (usec): min=145, max=85717, avg=553.99, stdev=4741.28
clat percentiles (usec):
| 1.00th=[ 147], 5.00th=[ 149], 10.00th=[ 151], 20.00th=[ 153],
| 30.00th=[ 155], 40.00th=[ 159], 50.00th=[ 167], 60.00th=[ 199],
| 70.00th=[ 229], 80.00th=[ 241], 90.00th=[ 249], 95.00th=[ 270],
| 99.00th=[ 374], 99.50th=[56576], 99.90th=[67072], 99.95th=[67072],
| 99.99th=[67072]
bw (KB /s): min= 6380, max= 7624, per=100.00%, avg=7202.00, stdev=111.69
lat (usec) : 2=0.01%, 50=0.01%, 250=90.56%, 500=8.76%, 750=0.06%
lat (usec) : 1000=0.02%
lat (msec) : 2=0.02%, 4=0.01%, 10=0.01%, 20=0.01%, 50=0.01%
lat (msec) : 100=0.55%
cpu : usr=0.50%, sys=1.98%, ctx=1080029, majf=0, minf=34
IO depths : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
submit : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
issued : total=r=1080027/w=0/d=0, short=r=0/w=0/d=0, drop=r=0/w=0/d=0
latency : target=0, window=0, percentile=100.00%, depth=1

Run status group 0 (all jobs):
READ: io=4218.9MB, aggrb=7200KB/s, minb=7200KB/s, maxb=7200KB/s, mint=600001msec, maxt=600001msec

Disk stats (read/write):
vdb: ios=1079640/0, merge=0/0, ticks=589523/0, in_queue=589382, util=98.27%

 

 

javascript中的Strict模式

javascript中的Strict模式

 

看动画学算法
以动画的方式,图文并茂讲解常用的算法和数据结构,包括各种排序算法、hash、栈、队列、链表、树、散列表、堆、图等,*对物有所值!
flydean程序那些事
¥39.90
订阅博主
文章目录
简介
使用Strict mode
strict mode的新特性
强制抛出异常
简化变量的使用
简化arguments
让javascript变得更加安全
保留关键字和function的位置
总结
简介
我们都知道javascript是一个弱类型语言,在ES5之前,javascript的程序编写具有很强的随意性,我可以称之为懒散模式(sloppy mode)。比如可以使用未定义的变量,可以给对象中的任意属性赋值并不会抛出异常等等。

在ES5中,引入了strict模式,我们可以称之为严格模式。相应的sloppy mode就可以被称为非严格模式。

严格模式并不是非严格模式的一个子集,相反的严格模式在语义上和非严格模式都发生了一定的变化,所以我们在使用过程中,一定要经过严格的测试。以保证在严格模式下程序的执行和非严格模式下的执行效果一致。

使用Strict mode
strict mode会改变javascript的一些表现,我们将会在下一节中进行详细的讲解。

这里先来看一下,怎么使用strict mode。

Strict mode主要用在一个完整的脚本或者function中,并不适用于block {}。 如果在block中使用strict mode是不会生效的。

除此之外,eval中的代码,Function代码,event handler属性和传递给WindowTimers.setTimeout()的string都可以看做是一个完整的脚本。我们可以在其中使用Strict mode。

如果是在script脚本中使用strict模式,可以直接在脚本的*上面加上”use strict”:

// 整个脚本的strict模式
‘use strict’;
var v = “Hi! I’m a strict mode script!”;
同样的我们也可以在function中使用strict模式:

function strict() {
// 函数的strict模式
‘use strict’;
function nested() { return ‘And so am I!’; }
return “Hi! I’m a strict mode function! ” + nested();
}
function notStrict() { return “I’m not strict.”; }

如果使用的是ES6中引入的modules,那么modules中默认就已经是strict模式了,我们不需要再额外的使用”use strict”:

function myModule() {
// 默认就是strict模式
}
export default myModule;
strict mode的新特性
strict mode在语法和运行时的表现上面和非严格模式都发生了一定的变化,接下来,我们一一来看。

强制抛出异常
在js中,有很多情况下本来可能是错误的操作,但是因为语言特性的原因,并没有抛出异常,从而导致*终运行结果并不是所期待的。

如果使用strict模式,则会直接抛出异常。

比如在strict模式中,不允许使用未定义的全局变量:

‘use strict’;

globalVar = 10; //ReferenceError: globalVar is not defined
这样实际上可以避免手误导致变量名字写错而导致的问题。

我再看一些其他的例子:

‘use strict’;

// 赋值给不可写的全局变量,
var undefined = 5; // throws a TypeError
var Infinity = 5; // throws a TypeError

// 赋值给不可写的属性
var obj1 = {};
Object.defineProperty(obj1, ‘x’, { value: 42, writable: false });
obj1.x = 9; // throws a TypeError

// 赋值给一个get方法
var obj2 = { get x() { return 17; } };
obj2.x = 5; // throws a TypeError

// 赋值给一个禁止扩展的对象
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = ‘ohai’; // throws a TypeError

Strict模式可以限制删除不可删除的属性,比如构造函数的prototype:

‘use strict’;
delete Object.prototype; // throws a TypeError

禁止对象和函数参数中的重复属性:

‘use strict’;
var o = { p: 1, p: 2 }; // Duplicate declaration

function sum(a, a, c) { // Duplicate declaration
‘use strict’;
return a + a + c;
}
禁止设置基础类型的属性:

(function() {
‘use strict’;

false.true = ”; // TypeError
(14).sailing = ‘home’; // TypeError
‘with’.you = ‘far away’; // TypeError

})();

简化变量的使用
使用Strict模式可以简化变量的使用,让程序代码可读性更强。

首先,strict模式禁止使用with。

with很强大,我们可以通过将对象传递给with,从而影响变量查找的scope chain。也就是说当我们在with block中需要使用到某个属性的时候,除了在现有的scope chain中查找之外,还会在with传递的对象中查找。

with (expression)
statement

使用with通常是为了简化我们的代码,比如:

var a, x, y;
var r = 10;

with (Math) {
a = PI * r * r;
x = r * cos(PI);
y = r * sin(PI / 2);
}

上面的例子中,PI是Math对象中的变量,但是我们可以在with block中直接使用。有点像java中的import的感觉。

下面的例子将会展示with在使用中的问题:

function f(x, o) {
with (o) {
console.log(x);
}
}
们在with block中输出x变量,从代码可以看出f函数传入了一个x变量。但是如果with使用的对象中如果也存在x属性的话,就会出现意想不到的问题。

所以,在strict模式中,with是禁止使用的。

其次是对eval的改动。

传统模式中,eval中定义的变量,将会自动被加入到包含eval的scope中。我们看个例子:

var x = 17;
var evalX = eval(“var x = 42; x;”);
console.log(x);

因为eval中引入了新的变量x,这个x的值将会覆盖*开始定义的x=17. *后我们得到结果是42.

如果加入use strict,eval中的变量将不会被加入到现有的Scope范围中,我们将会得到结果17.

var x = 17;
var evalX = eval(“‘use strict’; var x = 42; x;”);
console.log(x);
这样做的好处是为了避免eval对现有程序逻辑的影响。

在strict模式下面,还不允许delete name:

‘use strict’;

var x;
delete x; // !!! syntax error

eval(‘var y; delete y;’); // !!! syntax error~~

简化arguments
在js中,arguments代表的是参数数组,首先在Strict模式下,arguments是不能作为变量名被赋值的:

‘use strict’;
arguments++;
var obj = { set p(arguments) { } };
try { } catch (arguments) { }
function arguments() { }
var f = new Function(‘arguments’, “‘use strict’; return 17;”);

上面执行都会报错。

另外,在普通模式下,arguments是和命名参数相绑定的,并且arguments[0]和arg同步变化,都表示的是*个参数。

但是如果在strict模式下,arguments表示的是真正传入的参数。

我们举个例子:

function f(a) {
a = 42;
return [a, arguments[0]];
}
var pair = f(17);
console.log(pair[0]); // 42
console.log(pair[1]); // 42

上面的例子中,arguments[0]是和命名参数a绑定的,不管f传入的是什么值,arguments[0]的值*后都是42.

如果换成strict模式:

function f(a) {
‘use strict’;
a = 42;
return [a, arguments[0]];
}
var pair = f(17);
console.log(pair[0]); // 42
console.log(pair[1]); // 17

这个模式下arguments[0]接收的是实际传入的参数,我们得到结果17.

在Strict模式下,arguments.callee是被禁用的。通常来说arguments.callee指向的是当前执行的函数,这会阻止虚拟机对内联的优化,所以在Strict模式下是禁止的。

让javascript变得更加安全
在普通模式下,如果我们在一个函数f()中调用this,那么this指向的是全局对象。在strict模式下,这个this的值是undefined。

如果我们是通过call或者apply来调用的话,如果传入的是primitive value(基础类型),在普通模式下this会自动指向其box类(基础类型对应的Object类型,比如Boolean,Number等等)。如果传入的是undefined和null,那么this指向的是global Object。

而在strict模式下,this指向的是传入的值,并不会做转换或变形。

下面的值都是true:

‘use strict’;
function fun() { return this; }
console.assert(fun() === undefined);
console.assert(fun.call(2) === 2);
console.assert(fun.apply(null) === null);
console.assert(fun.call(undefined) === undefined);
console.assert(fun.bind(true)() === true);

为什么会安全呢?这就意味着,在strict模式下,不能通过this来指向window对象,从而保证程序的安全性。

另外,在普通模式下,我们可以通过fun.caller或者fun.arguments来获取到函数的调用者和参数,这有可能会访问到一些private属性或者不安全的变量,从而造成安全问题。

在strict模式下,fun.caller或者fun.arguments是禁止的。

function restricted() {
‘use strict’;
restricted.caller; // throws a TypeError
restricted.arguments; // throws a TypeError
}
function privilegedInvoker() {
return restricted();
}
privilegedInvoker();

保留关键字和function的位置
为了保证JS标准的后续发展,在strict模式中,不允许使用关键字作为变量名,这些关键字包括implements, interface, let, package, private, protected, public, static 和 yield等。

function package(protected) { // !!!
‘use strict’;
var implements; // !!!

interface: // !!!
while (true) {
break interface; // !!!
}

function private() { } // !!!
}
function fun(static) { ‘use strict’; } // !!!

而对于function来说,在普通模式下,function是可以在任何位置的,在strict模式下,function的定义只能在脚本的顶层或者function内部定义:

‘use strict’;
if (true) {
function f() { } // !!! syntax error
f();
}

for (var i = 0; i < 5; i++) {
function f2() { } // !!! syntax error
f2();
}

function baz() { // kosher
function eit() { } // also kosher
}

总结
Strict模式为JS的后续发展和现有编程模式的规范都起到了非常重要的作用。但是如果我们在浏览器端使用的话,还是需要注意浏览器的兼容性,并做好严格的测试。

浅谈分布式数据库

一 分布式数据库出现的场景:

1.单表数据量爆炸,>1000w,>1亿,>10亿,各种数据操作(CRUD)效率很低 。 关系型数据库在大于一定数据量的情况下检索性能会急剧下降。在面对互联网海量数据情况时,所有数据都存于一张表,显然会轻易超过数据库表可承受的数据量阀值。这个单表可承受的数据量阀值,需根据数据库和并发量的差异,通过实际测试获得。

2.单机数据库的瓶颈问题,处理不了高强度io。现代企业程序的瓶颈问题是数据库的瓶颈问题,所以数据库只做存储用,不再使用触发器,事物;

3.为了方便扩展,动态增加数据库节点,保证扩展性好

4.不同业务对应不同业务数据库,即使某个数据库挂了,不影响其他数据库对应的服务使用,服务高可用。

5.数据备份,数据*重要。

 

二 一些基本概念

单库:单机数据库 所有表存在一个库里,

分片(sharding),分片解决扩展性问题,属于水平拆分,引入分片,就引入了数据路由和分区键的概念。分表解决的是数据量过大的问题,分库解决的是数据库性能瓶颈的问题。

分组(group),分组解决可用性问题,分组通常通过主从复制(replication)的方式实现

互联网公司数据库实际软件架构是(大数据量下):又分片,又分组

单纯的分表虽然可以解决数据量过大导致检索变慢的问题,但无法解决过多并发请求访问同一个库,导致数据库响应变慢的问题。所以通常水平拆分都至少要采用分库的方式,用于一并解决大数据量和高并发的问题。这也是部分开源的分片数据库中间件只支持分库的原因。

​ 但分表也有不可替代的适用场景。*常见的分表需求是事务问题。同在一个库则不需考虑分布式事务,善于使用同库不同表可有效避免分布式事务带来的麻烦。目前强一致性的分布式事务由于性能问题,导致使用起来并不一定比不分库分表快,分局也无需要,大所述只需要保证事物的*终一致性。分表的另一个存在的理由是,过多的数据库实例不利于运维管理。

 

如何实现分库分表(后面去研究一致性raft算法)

​ 1) dao层,首先通过分区键算出库名表名(如shardKey%shardNum 算出来表index如y,然后y/(shardNum/sourceNum)=x,y是表下标,x是库下标)。
​ 2) 把source从spring容器中拿出来,把表名当参数传进去,拼成分片后的sql。
​ 3) 思路大概是(select … from order where … -> 先拿到db_x的source 然后 select … from order_y where …)

%title插图%num

Cobar介绍

Cobar是阿里巴巴(B2B)部门开发的一种关系型数据的分布式处理系统,它可以在分布式的环境下看上去像传统数据库一样为您提供海量数据服务。那么具体说说我们为什么要用它,或说cobar–能干什么?以下是我们业务运行中会存在的一些问题:
1.随着业务的进行数据库的数据量和访问量的剧增,需要对数据进行水平拆分来降低单库的压力,而且需要高效且相对透明的来屏蔽掉水平拆分的细节。
2.为提高访问的可用性,数据源需要备份。
3.数据源可用性的检测和failover。
4.前台的高并发造成后台数据库连接数过多,降低了性能,怎么解决。
针对以上问题就有了cobar施展自己的空间了,cobar中间件以proxy的形式位于前台应用和实际数据库之间,对前台的开放的接口是mysql通信协议。将前台SQL语句变更并按照数据分布规则转发到合适的后台数据分库,再合并返回结果,模拟单库下的数据库行为。

 

 

网上找到的关于cobar的一些不完美的地方:

Cobar不支持将一张表,例如test表拆分成test_1, test_2, test_3…..放在同一个库中,必须将拆分后的表分别放入不同的库来实现分布式。
1) 不支持跨库情况下的join、分页、排序、子查询操作。
2) SET语句执行会被忽略,事务和字符集设置除外。
3) 分库情况下,insert语句必须包含拆分字段列名。
4) 分库情况下,update语句不能更新拆分字段的值。
5) 不支持SAVEPOINT操作。
6) 暂时只支持MySQL数据节点。
7) 使用JDBC时,不支持rewriteBatchedStatements=true参数设置(默认为false)。
8) 使用JDBC时,不支持useServerPrepStmts=true参数设置(默认为false)。
9) 使用JDBC时,BLOB, BINARY, VARBINARY字段不能使用setBlob()或setBinaryStream()方法设置参数。

 

快速检测服务器漏洞

Shodan是互联网上*可怕的搜索引擎

CNNMoney的一篇文章写道,虽然目前人们都认为谷歌是*强劲的搜索引擎,但Shodan才是互联网上*可怕的搜索引擎。

与谷歌不同的是,Shodan不是在网上搜索网址,而是直接进入互联网的背后通道。Shodan可以说是一款“黑暗”谷歌,一刻不停的在寻找着所有和互联网关联的服务器、摄像头、打印机、路由器等等。每个月Shodan都会在大约5亿个服务器上日夜不停地搜集信息。

本文以百度www.baidu.com为例检测百度服务器的漏洞。

地址:https://www.shodan.io/

搜索形式建议采用ip地址这种形式

首先需要获取到百度的ip地址

cmd->ping www.baidu.com
%title插图%num

发现我本机访问的百度服务器IP地址为:61.135.169.125

下来我们将在https://www.shodan.io/搜索这个地址

%title插图%num

下面我们看看搜索结果

%title插图%num

搜索另一个网站,也可以使用域名,比如我们搜索淘宝www.taobao.com

可以发现淘宝在地球上面是有2000多台服务器的

%title插图%num

我来搜索一下自己的网站www.jqqhappy.club

ip地址为:39.105.165.135

%title插图%num

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速