I have an ActiveX communication driver for TCP / IP that allows me to read and write to a PLC from an Excel file. I want to write the value 5 MW having another 5 cells in Excel, I tried it with loop and I wrote in the 5 variables at a time only one value. Now I have a "Select Case" it does not work me. Please help. The code is as follows:
For tt = 1 To 5
valor(1) = Val(Cells(1, 4).Value)
valor(2) = Val(Cells(2, 4).Value)
valor(3) = Val(Cells(3, 4).Value)
valor(4) = Val(Cells(4, 4).Value)
valor(5) = Val(Cells(5, 4).Value)
Next tt
Select Case valor(tt)
Case valor(1)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 5, 1, 1000, 300, valor)
Case valor(2)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 6, 1, 1000, 300, valor)
Case valor(3)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 7, 1, 1000, 300, valor)
Case valor(4)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 8, 1, 1000, 300, valor)
Case valor(5)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 9, 1, 1000, 300, valor)
End Select
The line:
MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 9, 1, 1000, 300, valor)
Are the parameters of communication with the PLC to Settings. The last parameter is the value we need to write, which I gather from a cell.
The code is VBA in Excel 2002.
THANKS!!!
try this
For tt = 1 To 5
valor(1) = Val(Cells(1, 4).Value)
valor(2) = Val(Cells(2, 4).Value)
valor(3) = Val(Cells(3, 4).Value)
valor(4) = Val(Cells(4, 4).Value)
valor(5) = Val(Cells(5, 4).Value)
Select Case valor(tt)
Case valor(1)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 5, 1, 1000, 300, valor)
Case valor(2)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 6, 1, 1000, 300, valor)
Case valor(3)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 7, 1, 1000, 300, valor)
Case valor(4)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 8, 1, 1000, 300, valor)
Case valor(5)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 9, 1, 1000, 300, valor)
End Select
Next tt
As cboden pointed out the select-statement is outside of the for-loop. Instead of implementing a select-statement you should do it like this (read the rest of this post for an explanation):
For tt = 1 To 5
valor = Val(Cells(tt, 4).Value)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 4+tt, 1, 1000, 300, valor)
Next tt
Explanation:
Keep in mind that the for-loop will run all code inside the loop once for each value of tt (1,2,3,4,5), which means that this:
For tt = 1 To 5
valor(1) = Val(Cells(1, 4).Value)
valor(2) = Val(Cells(2, 4).Value)
valor(3) = Val(Cells(3, 4).Value)
valor(4) = Val(Cells(4, 4).Value)
valor(5) = Val(Cells(5, 4).Value)
Next tt
Can (and should) be written like this:
For tt = 1 To 5
valor(tt) = Val(Cells(tt, 4).Value)
Next tt
The select-statement is not only wrong but also unecessary. The correct version (if you choose to put it in the for-loop, which I do not recommend since it is redundant and makes the code harder to read) is:
Select Case tt
Case 1
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 5, 1, 1000, 300, valor(1))
Case 2
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 6, 1, 1000, 300, valor(2))
Case 3
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 7, 1, 1000, 300, valor(3))
Case 4
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 8, 1, 1000, 300, valor(4))
Case 5
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 9, 1, 1000, 300, valor(5))
End Select
The above can be shortened to:
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 4+tt, 1, 1000, 300, valor(tt))
for each value of tt (1,2,3,4,5) and if put into the for-loop together with valor(tt) = Val(Cells(tt, 4).Value) will form:
For tt = 1 To 5
valor(tt) = Val(Cells(tt, 4).Value)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 4+tt, 1, 1000, 300, valor(tt))
Next tt
Since we do not need to keep the array of valor we can remove the valor(tt) and replace it with valor, thus making the finished code:
For tt = 1 To 5
valor = Val(Cells(tt, 4).Value)
res2 = MB1.Write("10.56.35.214", "10.56.35.22", 502, 0, 16, 4+tt, 1, 1000, 300, valor)
Next tt
Also I would suggest that you, in the future, refrain from posting IP-addresses in such a public forum.
Related
I am working on a program that reads logfiles in, in a weird format.
I have the following code reading from a number of logfiles
(logFiles)
It works fine to itterate through them and so on. The problem is that for some reason the last element that i append to the list dataList overwrites the entire list so all fields are the same..
def fetchDataFromLogFiles(colIndex, colNames, colType, logFiles):
dataList = []
rowchange = []
row = []
for i in range(0, len(colIndex)):
row.append(0)
rowchange.append(0)
for x in range(0, len(logFiles)):
print("fetching data from: ")
print(logFiles[x])
logFile = open(logFiles[x] , "r")
for x in range(0,4):
line = logFile.readline()
if not line:
break
else:
line = line.split(",")
TimeStamp = line[1]
rest = line[2:]
#TimeDate formatting
whiteSpaces = len(TimeStamp)- len(TimeStamp.lstrip())
TimeStamp = TimeStamp[whiteSpaces:]
TimeStampFormat = "%a %b %d %H:%M:%S %Y"
DT = datetime.datetime.strptime(TimeStamp, TimeStampFormat)
#print(type(DT))
#print(DT)
row[0] = DT
rowchange[0] +=1
for i in range(0, len(rest)):
rest[i] = rest[i].replace(" ","")
if(i%2 == 0):
try:
index = colIndex.index(rest[i])
rowchange[index] += 1
if(colType[index] == "Bool"):
if(rest[i+1] == "0"):
row[index] = False
#print(type(row[index]))
else:
row[index] = True
#print(type(row[index]))
elif(colType[index] == "Short"):
row[index] = int(rest[i+1])
#print(type(row[index]))
else:
row[index] = rest[i+1]
except:
continue
print(x)
print(row[0])
dataList.append(row)
print(dataList[x][0])
logFile.close()
print("file closed")
for x in range (0,len(dataList)):
print(dataList[x][0])
return dataList
Debug print output as follows to show what i mean
0
2022-01-24 04:57:39
2022-01-24 04:57:39
1
2022-01-24 04:57:39
2022-01-24 04:57:39
2
2022-01-24 04:57:39
2022-01-24 04:57:39
3
2022-01-24 04:57:40
2022-01-24 04:57:40
file closed
2022-01-24 04:57:40
2022-01-24 04:57:40
2022-01-24 04:57:40
2022-01-24 04:57:40
A couple of lines of log file:
$1, Mon Jan 24 04:57:39 2022,$2,10,$3,42,$4, 0,$5, 1, #0, 42, #1, 130, #2, 144, #3, 49, #4, 45, #5, 66, #6, 2975, #7, -3981, #8, 4028, #9, 3900, #10, 2480, #13, 4029, #16, 2930, #17, 2190, #20, 102, #21, 2, #24, 2900, #25, 2200, #26, 6, #27, 51, #30, 2898, #31, 0, #32, 0, #33, 150, #34, 511, #35, -2, #36, 22, #37, 549, #38, -2, #39, 22, #40, 60, #41, 45, #42, 218, #43, -306, #45, 236, #46, -152, #48, 100, #49, 0, #50, 100, #51, 0, #52, 137, #53, -200, #55, 137, #56, -64, #58, 7850, #59, 1, #60, 8300, #61, 1, #62, 100, #63, -1, #64, 60, #65, 88, #66, 86, #67, 108, #68, 1, #73, 1800, #74, 2500, #76, 0, #77, 0, #78, 0, #79, 0, #80, 0, #81, 173, #82, 174, #83, 0, #84, 0, #85, -11, #86, -100, #88, 400, #89, 2729, #90, 0, #91, 2762, #93, 5, #94, 15, #95, 11, #96, 99, #97, 30, #98, 0, #100, 0, #101, 0, #102, 0,#105, 1252, #106, 0, #107, 0, #108, 0,#109, 4029, #110, 0,#111, 3900,#112, 2480,#113, 2520,#114, 2200,#115, 2900, #116, 1, #117, 0, #118, 0, #119, 156, #120, 165, #121, 0, #123, 0, #124, 0, #126, 40, #127, 60, #128, 350, #129, 450, #130, 57,#131, 1740,#132, 1682, #133, 1, #134, 0, #135, 0, #136, 0, #137, 2, #138, 0, #141, 135, #142, 0,#150, 4800, #151, 0, #152, 0,#153, 4864, #154, 1, #155, 1, #156, 0, #157, 0, #158, 1, #160, 15, #161, 40, #162, 15, #163, 40, #164, 1, #165, 1, #166, 0,#170, 1000,#172, 3000, #173, 0, #175, 0, #179, 0, #180, 599, #181, 0, #182, 9, #183, 42, #184, 0, #185, 7, #186, 49, #187, 0, #188, 4, #189, 1, #190, 1,#191, 2261,#192, 1796, #193, 1, #194, 0, #197, 0,#199, 2000,#200, 10000, #201, 10, #202, 10,#203, 3000, #204, 0, #205, 900, #206, 0,#209, 1774, #210, 300, #211, 900,#212, 1800, #213, 100,#217, 3000,#218, 4500,#219, 1500,#220, 3000, #222, 60, #223, 9,#224, 3150, #225, 0, #226, 0, #231, 30, #232, 1, #233, 0, #234, 0, #235, 100, #236, 0, #237, 0, #240, 34, #241, 29, #251, 0,
$1, Mon Jan 24 04:57:39 2022,$2,10,$3,42,$4, 0,$5, 1, #8, 4029, #30, 2897, #82, 173, #141, 132,#153, 5120, #185, 8,
$1, Mon Jan 24 04:57:39 2022,$2,10,$3,42,$4, 0,$5, 1, #30, 2898, #91, 2761, #130, 17,#131, 1701,#132, 1683, #141, 130,#153, 5376, #155, 0, #185, 9,
$1, Mon Jan 24 04:57:40 2022,$2,10,$3,42,$4, 0,$5, 1, #7, -3982, #8, 4028, #89, 2731, #141, 128,#153, 5632, #185, 8,
After Ethans comment i edited the code to not use globals, but still have the same problem
I have a 2D numpy array my_data and I want to extract row i if the 4th column of row i has a 0 && the 4th column of row i-i has a 1.
I do this now using list comprehension but is there a "non-list" faster way to do this?
'''
my_data = array([(65535, 255, 0, 1, 1), (65535, 255, 0, 1, 1),
(65535, 255, 0, 1, 1), ..., (65535, 255, 0, 1, 1),
(65535, 255, 0, 1, 1), (65535, 255, 0, 1, 1)],
dtype=[('col_0', '<u2'), ('col_1', 'u1'), ('col_2', 'u1'), ('col_3', 'u1'), ('col_4', 'u1')])
filtered_data = [my_data[i] for i in range(1,len(my_data)) if (my_data[i][4] == 0 and my_data[i-1][4] == 1)]
'''
I noticed that your array is structured, with named columns,
so you can make some use of these features.
As a source array I used:
my_data = np.array([
(65535, 240, 0, 1, 1),
(65535, 241, 0, 1, 0),
(65535, 242, 0, 1, 1),
(65535, 243, 0, 1, 0),
(65535, 244, 0, 1, 1),
(65535, 245, 0, 1, 1)],
dtype=[('col_0', '<u2'), ('col_1', 'u1'), ('col_2', 'u1'),
('col_3', 'u1'), ('col_4', 'u1')])
The first step is to take the 4-th column and the same column again,
but shifted by 1 position to the right, inserting 0 as the initial
element:
c4 = my_data['col_4']
c4prev = np.insert(c4[:-1], 0, 0)
Both these arrays contain:
array([1, 0, 1, 0, 1, 1], dtype=uint8)
array([0, 1, 0, 1, 0, 1], dtype=uint8)
And to get the expected result use boolean indexing:
result = my_data[np.logical_and(c4 == 0, c4prev == 1)]
The result is:
array([(65535, 241, 0, 1, 0), (65535, 243, 0, 1, 0)],
dtype=[('col_0', '<u2'), ('col_1', 'u1'), ('col_2', 'u1'),
('col_3', 'u1'), ('col_4', 'u1')])
so just the intended rows have been extracted.
Is it possible to create a numerical range in M? For example something like:
let
x = range(1,10) // {1,2,3,4,5,6,7,8,9,10}, from 1 to 10, increment by 1
x = range(1,10,2) // {1,3,5,7,9}, from 1 to 10, increment by 2
For simple scenarios, a..b might be appropriate. Some examples:
let
firstList = {1..10}, // {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
secondList = {1, 5, 12, 14..17, 18..20}, // {1, 5, 12, 14, 15, 16, 17, 18, 19, 20}
thirdList = {Character.ToNumber("a")..100, 110..112}, // {97, 98, 99, 100, 110, 111, 112}
fourthList = {95..(10 * 10)} // {95, 96, 97, 98, 99, 100}
in
fourthList
Otherwise, maybe try a custom function which internally uses List.Generate:
let
range = (inclusiveStart as number, inclusiveEnd as number, optional step as number) as list =>
let
interval = if step = null then 1 else step,
conditionFunc =
if (interval > 0) then each _ <= inclusiveEnd
else if (interval < 0) then each _ >= inclusiveEnd
else each false,
generated = List.Generate(() => inclusiveStart, conditionFunc, each _ + interval)
in generated,
firstList = range(1, 10), // {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
secondList = range(1, 10, 2), // {1, 3, 5, 7, 9}
thirdList = range(1, 10 , -1), // {} due to the combination of negative "step", but "inclusiveEnd" > "inclusiveStart"
fourthList = range(10, 1, 0), // {} current behaviour is to return an empty list if 0 is passed as "step" argument.
fifthList = range(10, 1, -1), // {10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
sixthList = range(10, 1, 1) // {} due to the combination of positive "step", but "inclusiveEnd" < "inclusiveStart"
in
sixthList
The above range function should be able to generate both ascending and descending sequences (see examples in code).
Alternatively, you could create a custom function which uses List.Numbers internally by first calculating what the count argument needs to be. But I chose to go with List.Generate.
I'am need a coloring image 256 on 256 by values from the matrix.
Example:
I have a matrix [[-64, -64, -64], [-8, 10, 8], [10, 50, 22]], and colors for this values, -64 = (0, 0, 0, 255) -8 = (25, 25, 25, 255) 10 = (45, 255, 255, 255) etc.
How can I quickly fill the output_matrix with color tuppels and form image through Image.fromarray(color_matrix.astype('uint8'), 'RGBA')?
Function
def draw_tile(matrix: np.matrix, type: str, img_size: tuple) -> Image:
"""
Draws an image with the given data as the image size and the size of its values for x and y.
:param matrix: numpy matrix with all measurement data
:param type: descriptor defining how to draw the input data
:param img_size: image size
:return: image
"""
def doppler_var_dict(var: float):
return {
var <= -30: 13,
-30 < var <= -25: 0,
-25 < var <= -20: 1,
-20 < var <= -15: 2,
-15 < var <= -10: 3,
-10 < var <= -5: 4,
-5 < var <= 0: 5,
0 < var <= 1: 6,
1 < var <= 5: 7,
5 < var <= 10: 8,
10 < var <= 15: 9,
15 < var <= 20: 10,
20 < var <= 25: 11,
25 < var <= 30: 12,
var >= 30: 14,
}[1]
def rainfall_var_dict(var: float):
return {
var <= 0.2: 0,
0.2 < var <= 0.5: 1,
0.5 < var <= 1.5: 2,
1.5 < var <= 2.5: 3,
2.5 < var <= 4: 4,
4 < var <= 6: 5,
5 < var <= 10: 6,
10 < var <= 15: 7,
15 < var <= 20: 8,
20 < var <= 35: 9,
35 < var <= 50: 10,
50 < var <= 80: 11,
80 < var <= 120: 12,
120 < var <= 200: 13,
200 < var <= 300: 14,
var >= 300: 1
}[1]
def reflectivity_var_dict(var: float):
return {
var <= -4: 0,
-4 < var <= -3.5: 1,
-3.5 < var <= -3: 2,
-3 < var <= -2.5: 3,
-2.5 < var <= -.5: 4,
-.5 < var <= -0: 5,
-0 < var <= .25: 6,
.25 < var <= 0.5: 7,
.5 < var <= 1: 8,
1 < var <= 1.25: 9,
1.25 < var <= 1.5: 10,
1.5 < var <= 2: 11,
2 < var <= 2.5: 12,
2.5 < var <= 3: 13,
3 < var <= 3.5: 14,
3.5 < var <= 4: 15,
4 < var <= 5: 16,
5 < var <= 6: 17,
var >= 6: 18
}[1]
doppler_color = [(0, 0, 0, 0), (55, 255, 195, 150), (0, 250, 255, 150), (0, 195, 255, 150),
(0, 100, 255, 150), (0, 0, 255, 150), (140, 140, 140, 150), (150, 0, 0, 150), (255, 0, 0, 150),
(255, 85, 0, 150), (255, 165, 0, 150), (255, 165, 80, 150), (255, 230, 130, 150),
(65, 65, 65, 150),
(255, 255, 0, 150)]
rainfall_color = [(0, 0, 0, 0), (200, 200, 200, 150), (180, 180, 255, 150), (120, 120, 255, 150),
(20, 20, 255, 150), (0, 216, 195, 150), (0, 150, 144, 150), (0, 102, 102, 150),
(255, 255, 0, 150),
(255, 200, 0, 150), (255, 150, 0, 150), (255, 100, 0, 150), (255, 0, 0, 150), (200, 0, 0, 150),
(120, 0, 0, 150), (40, 0, 0, 150)]
z_d_r_color = [(90, 0, 150, 150), (115, 0, 255, 150), (213, 0, 255, 150), (255, 0, 0, 150), (176, 0, 0, 150),
(255, 85, 0, 150), (255, 220, 0, 150), (119, 255, 0, 150), (0, 255, 255, 150), (0, 255, 162, 150),
(0, 162, 255, 150), (0, 0, 255, 150), (255, 0, 77, 150), (50, 2, 163, 150), (173, 173, 173, 150),
(145, 145, 145, 150), (120, 120, 120, 150), (92, 92, 92, 150), (60, 60, 60, 150), (0, 0, 0, 0)]
z_d_r_color = list(reversed(z_d_r_color))
dict_dicts = {
DOPPLER_RADIAL: doppler_var_dict,
RADAR_RAINFALL: rainfall_var_dict,
HORIZONTAL: reflectivity_var_dict,
DIFFERENTIAL: reflectivity_var_dict
}
color_map_dict = {
DOPPLER_RADIAL: doppler_color,
RADAR_RAINFALL: rainfall_color,
HORIZONTAL: z_d_r_color,
DIFFERENTIAL: z_d_r_color
}
var_dict = dict_dicts[type]
try:
color_shem = color_map_dict[type]
except KeyError as ee:
return HttpResponseServerError('Error in bufr_image: wrong data type')
with timer.Profiler('color_matrix time'):
color_matrix = np.array(list(map(lambda var: color_shem[var_dict(var)], matrix.reshape(-1))))
color_matrix = color_matrix.reshape((img_size[0], img_size[1], 4))
img = Image.fromarray(color_matrix.astype('uint8'), 'RGBA')
return img
Can you suggest an algorithm that will work in less than a second for the matrix 256 by 256?
I have a method which does a series of calculations which take quite a bit of time to complete. The objects that this method does computations on are generated at runtime and can range from a few to a few thousand. Obviously it would be better if I could run these computations across several threads concurrently, but when I try that, my program uses more CPU yet takes longer than running them one-by-one. Any ideas why?
let itemsPerThread = (dataArray.count / 4) + 1
for var i = 0; i < dataArray.count; i += itemsPerThread
{
let name = "ComputationQueue\(i)".bridgeToObjectiveC().cString()
let compQueue = dispatch_queue_create(name, DISPATCH_QUEUE_CONCURRENT)
dispatch_async(compQueue,
{
let itemCount = i + itemsPerThread < dataArray.count ? itemsPerThread : dataArray.count - i - 1
let subArray = dataArray.bridgeToObjectiveC().subarrayWithRange(NSMakeRange(i, dataCount)) as MyItem[]
self.reallyLongComputation(subArray, increment: increment, outputIndex: self.runningThreads-1)
})
NSThread.sleepForTimeInterval(1)
}
Alternatively:
If I run this same thing, but a single dispatch_async call and on the whole dataArray rather than the subarrays, it completes much faster while using less CPU.
what you (it is my guess) want to do should looks like
//
// main.swift
// test
//
// Created by user3441734 on 12/11/15.
// Copyright © 2015 user3441734. All rights reserved.
//
import Foundation
let computationGroup = dispatch_group_create()
var arr: Array<Int> = []
for i in 0..<48 {
arr.append(i)
}
print("arr \(arr)")
func job(inout arr: Array<Int>, workers: Int) {
let count = arr.count
let chunk = count / workers
guard chunk * workers == count else {
print("array.cout divided by workers must by integer !!!")
return
}
let compQueue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT)
let syncQueue = dispatch_queue_create("aupdate", DISPATCH_QUEUE_SERIAL)
for var i = 0; i < count; i += chunk
{
let j = i
var tarr = arr[j..<j+chunk]
dispatch_group_enter(computationGroup)
dispatch_async(compQueue) { () -> Void in
for k in j..<j+chunk {
// long time computation
var z = 100000000
repeat {
z--
} while z > 0
// update with chunk
tarr[k] = j
}
dispatch_async(syncQueue, { () -> Void in
for k in j..<j+chunk {
arr[k] = tarr[k]
}
dispatch_group_leave(computationGroup)
})
}
}
dispatch_group_wait(computationGroup, DISPATCH_TIME_FOREVER)
}
var stamp: Double {
return NSDate.timeIntervalSinceReferenceDate()
}
print("running on dual core ...\n")
var start = stamp
job(&arr, workers: 1)
print("job done by 1 worker in \(stamp-start) seconds")
print("arr \(arr)\n")
start = stamp
job(&arr, workers: 2)
print("job done by 2 workers in \(stamp-start) seconds")
print("arr \(arr)\n")
start = stamp
job(&arr, workers: 4)
print("job done by 4 workers in \(stamp-start) seconds")
print("arr \(arr)\n")
start = stamp
job(&arr, workers: 6)
print("job done by 6 workers in \(stamp-start) seconds")
print("arr \(arr)\n")
with results
arr [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]
running on dual core ...
job done by 1 worker in 5.16312199831009 seconds
arr [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
job done by 2 workers in 2.49235796928406 seconds
arr [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24]
job done by 4 workers in 3.18479603528976 seconds
arr [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36]
job done by 6 workers in 2.51704299449921 seconds
arr [0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40]
Program ended with exit code: 0
... you can use next pattern for distributing job between any number of workers (the number of workers which give you the best performance depends on worker definition and sources which are available in your environment). generally for any kind of long time calculation ( transformation ) you can expect some performance gain. in two core environment up to 50%. if your worker use highly optimized functions using more cores 'by default', the performance gain can be close to nothing :-)
// generic implementation
// 1) job distribute data between workers as fair, as possible
// 2) workers do their task in parallel
// 3) the order in resulting array reflect the input array
// 4) there is no requiremets of worker block, to return
// the same type as result of yor 'calculation'
func job<T,U>(arr: [T], workers: Int, worker: T->U)->[U] {
guard workers > 0 else { return [U]() }
var res: Dictionary<Int,[U]> = [:]
let workersQueue = dispatch_queue_create("workers", DISPATCH_QUEUE_CONCURRENT)
let syncQueue = dispatch_queue_create("sync", DISPATCH_QUEUE_SERIAL)
let group = dispatch_group_create()
var j = min(workers, arr.count)
var i = (0, 0, arr.count)
var chunk: ArraySlice<T> = []
repeat {
let a = (i.1, i.1 + i.2 / j, i.2 - i.2 / j)
i = a
chunk = arr[i.0..<i.1]
dispatch_group_async(group, workersQueue) { [i, chunk] in
let arrs = chunk.map{ worker($0) }
dispatch_sync(syncQueue) {[i,arrs] in
res[i.0] = arrs
}
}
j--
} while j != 0
dispatch_group_wait(group, DISPATCH_TIME_FOREVER)
let idx = res.keys.sort()
var results = [U]()
idx.forEach { (idx) -> () in
results.appendContentsOf(res[idx]!)
}
return results
}
You need to
Get rid of the 1 second sleep. This is artifically reducing the degree to which you get parallel execution, because you're waiting before starting the next thread. You are starting 4 threads - and you are therefore artifically delaying the start (and potentially the finish) of the final thread by 3 seconds.
Use a single concurrent queue, not one per dispatch block. A concurrent queue will start blocks in the order in which they are dispatched, but does not wait for one block to finish before starting the next one - i.e. it will run blocks in parallel.
NSArray is a thread-safe class. I presume that it uses a multiple-reader/single-writer lock internally, which means there is probably no advantage to be obtained from creating a set of subarrays. You are, however, incurring the overhead of creating the subArray
Multiple threads running on different cores cannot talk to the same cache line at the same time.Typical cache line size is 64 bytes, which seems unlikely to cause a problem here.