我知道swift会优化复制写入数组,但它会为所有结构执行此操作吗?例如:
<script>
var dy = {
instanceAlias : {}
};
var CATEGORIES = ["a1","a2","a3","a4","a5","a6","a7","a8","a9","a10","a11","a12","a13","a14","a15","a16","a17","a18","a19","a20"];
var THEME = "";
var HEIGHT = "290";
var highchartConfig = {
column : {
chart: {
renderTo: null,
type: 'column'
},
xAxis: {
gridLineWidth: 1,
tickLength: 4,
categories : null,
labels : {
rotation: 0,
formatter : function(d){
return dy.instanceAlias[this.value] || this.value;
}
}
},
yAxis: {
min : 0,
max : 5,
lineWidth: 1,
tickLength: 4, // Same value as offset
tickPosition: "outside",
tickWidth: 1,
tickAmount: 3,
tickInterval : 25,
title: {
style : {
display: 'none'
}
},
stackLabels: {
style : {
"fontWeight": "normal",
color : (THEME == "dark") ? "#b0b0b3" : "#000"
}
}
},
plotOptions: {
series: {
borderRadius: 6,
borderWidth: 0,
marker :{
enabled :true,
symbol : "circle",
radius : 4
}
}
},
series: null
}
};
var stack1Config = $.extend(true,{},highchartConfig.column,{
colors : ["#009651","#ff9800","#ff1100","#009651"], //stack colors
chart: {
animation: false,
renderTo: "stack1",
height : HEIGHT
},
xAxis: {
categories : CATEGORIES
},
title: {
style: {
display: 'none'
}
},
subtitle: {
style: {
display: 'none'
}
},
legend : false,
tooltip : false,
yAxis: {
max : null,
tickInterval : null,
tickLength : null,
stackLabels: {
enabled: true,
useHTML : false,
style : {
"fontWeight": "normal",
color : (THEME == "dark") ? "#b0b0b3" : "#000"
}
}
},
plotOptions: {
column: {
stacking: 'normal',
},
series: {
animation: false,
stickyTracking: false,
enableMouseTracking: false,
lineWidth: 0,
marker: {
enabled : true,
symbol : "circle",
radius : 4
},
}
},
series : (function(){
var series = new Array();
var stack = [
{id : "normal", alias : "normal"},
{id : "warning", alias : "warning"},
{id : "danger", alias : "danger"}
];
for (var i = 0; i < stack.length; i++) {
//stack column 브러시 추가.
series.push({
name : stack[i].alias || stack[i].id,
id : stack[i].id,
lineWidth: 1,
data : (function(categories){
var data = [];
for (var i = 0; i < categories.length; i++) {
data.push(0);
}
return data;
})(CATEGORIES)
});
}
//circle
series.push({
type : "scatter",
name : "scatter",
id : "scatter",
marker: {
fillColor: '#FFFFFF',
lineWidth: 1,
lineColor: null
},
data : (function(b){
var data = [];
for (var i = 0; i < b.length; i++) {
data.push(0);
}
return data;
})(CATEGORIES)
});
console.log(series)
return series;
})()
});
var stack2Config = $.extend(true,{},highchartConfig.column,{
colors :["#009651"],
chart: {
animation: false,
renderTo: "stack2",
height : HEIGHT
},
xAxis: {
categories : CATEGORIES
},
title: {
style: {
display: 'none'
}
},
subtitle: {
style: {
display: 'none'
}
},
legend : false,
tooltip : false,
yAxis: {
max : null,
tickInterval : null,
tickLength : null,
stackLabels: {
enabled: true,
useHTML : false,
style : {
"fontWeight": "normal",
color : (THEME == "dark") ? "#b0b0b3" : "#000"
}
}
},
plotOptions: {
animation: false,
stickyTracking: false,
enableMouseTracking: false,
lineWidth: 0,
marker : {
enabled : false
},
column : {
dataLabels: {
enabled: true,
useHTML: true,
x : 0,
y : 0,
style : {
"fontWeight": "normal"
}
}
}
},
series : (function(){
var series = new Array();
var stack = [
{id : "cpu", alias : "CPU"}
];
for (var i = 0; i < stack.length; i++) {
//stack column 브러시 추가.
series.push({
name : stack[i].alias || stack[i].id,
id : stack[i].id,
lineWidth: 1,
data : (function(categories){
var data = [];
for (var i = 0; i < categories.length; i++) {
data.push(0);
}
return data;
})(CATEGORIES)
});
}
//circle
series.push({
type : "scatter",
name : "scatter",
id : "scatter",
marker: {
fillColor: '#FFFFFF',
lineWidth: 1,
lineColor: null
},
data : (function(b){
var data = [];
for (var i = 0; i < b.length; i++) {
data.push(0);
}
return data;
})(CATEGORIES)
});
console.log(series)
return series;
})()
});
var stack1 = Highcharts.chart(stack1Config);
var stack2 = Highcharts.chart(stack2Config);
var alarmTimeoutId = null;
var alarmTimeout = function(){
return setTimeout(function(){
var ACT_COLUMN = {
normal : [],
warning : [],
danger : [],
scatter : [] // success,warning,danger total value
};
var length = 20;
for (var i = 0; i < length; i++) {
var normalCnt = Math.round(Math.random()*100);
var warningCnt = Math.round(Math.random()*100);
var dangerCnt = Math.round(Math.random()*100);
ACT_COLUMN.scatter.push({ y: normalCnt+warningCnt+dangerCnt });
ACT_COLUMN.normal.push(normalCnt);
ACT_COLUMN.warning.push(warningCnt);
ACT_COLUMN.danger.push(dangerCnt);
}
for (var key in ACT_COLUMN) {
stack1.get(key).setData(ACT_COLUMN[key],false,false);
}
stack1.xAxis[0].setCategories(CATEGORIES);
ACT_COLUMN.scatter = null;
ACT_COLUMN.normal = null;
ACT_COLUMN.warning = null;
ACT_COLUMN.danger = null;
ACT_COLUMN = null;
var cpuData = [];
for (var i = 0; i < length; i++) {
var cpu = Math.round(Math.random()*100);
var color = "#009651";
if(cpu <= 50){
color = "#009651";
}else if(cpu <= 80){
color = "#ff9800";
}else{
color = "#ff1100";
}
cpuData.push({y : cpu, color : color });
}
var series = stack2.series;
var seriesLength = series.length;
for (var i = 0; i < seriesLength; i++) {
series[i].setData(cpuData,false,false);
}
stack2.xAxis[0].setCategories(CATEGORIES);
clearTimeout(alarmTimeoutId);
alarmTimeoutId = alarmTimeout();
}, 2000);
}
alarmTimeout();
</script>
答案 0 :(得分:28)
Array
已实现具有写时复制行为 - 无论编译器优化如何,您都可以获得它(当然,优化可以减少案例数量)副本需要发生)。
在基本级别,Array
只是一个结构,它包含对包含元素的堆分配缓冲区的引用 - 因此多个Array
实例可以引用相同的缓冲。当你来改变给定的数组实例时,实现将检查缓冲区是否被唯一引用,如果是,则直接改变它。否则,该数组将执行底层缓冲区的副本,以保留值语义。
但是,使用Point
结构时,您并未在语言级别实施写时复制。当然,作为@Alexander says,这并不能阻止编译器执行各种优化以最小化复制整个结构的成本。这些优化不需要遵循写时复制的确切行为 - 只要程序根据语言规范运行,编译器就可以随心所欲地执行它想要的任何。 / p>
在您的具体示例中,p1
和p2
都是全局的,因此编译器需要使它们成为不同的实例,因为同一模块中的其他.swift文件可以访问它们(尽管这可能可能通过整个模块优化进行优化)。但是,编译器仍然不需要复制实例 - 它只能evaluate the floating-point addition at compile-time并使用0.0
初始化其中一个全局变量,而使用1.0
初始化其中一个全局变量。
如果它们是函数中的局部变量,例如:
struct Point {
var x: Float = 0
}
func foo() {
var p1 = Point()
var p2 = p1
p2.x += 1
print(p2.x)
}
foo()
编译器甚至不必创建两个Point
实例 - 它只能创建一个初始化为1.0
的浮点局部变量,并打印出来。
关于将值类型作为函数参数传递,对于足够大的类型和(在结构的情况下)利用其足够属性的函数,编译器can pass them by reference而不是复制。然后被调用者只能在需要时复制它们,例如在需要使用可变副本时。
在通过值传递结构的其他情况下,编译器也可以specialise functions进行复制,以便仅复制函数所需的属性。
以下代码:
struct Point {
var x: Float = 0
var y: Float = 1
}
func foo(p: Point) {
print(p.x)
}
var p1 = Point()
foo(p: p1)
假设foo(p:)
没有被编译器内联(在这个例子中,但是一旦它的实现达到一定的大小,编译器就不会认为值得) - 编译器可以将功能专门化为:
func foo(px: Float) {
print(px)
}
foo(px: 0)
它只会将Point
&#39; x
属性的值传递给函数,从而节省了复制y
属性的成本。
因此编译器将尽其所能以减少值类型的复制。但是在不同情况下进行了如此多的各种优化,你不能简单地将任意值类型的优化行为简化为只写拷贝。