Вероятно, вы можете оптимизировать кеш с помощью цикла SIMD, который читает, может быть, 8 или 12 полных векторов строк, а затем те же строки для следующего столбца. (То есть для 32-битных элементов, 8 * 4 или 8 * 8 строк параллельно). Вы используете MSVC, который поддерживает встроенные функции x86 SSE2 / AVX2, такие как _mm256_load_ps
и _mm256_max_ps
или _mm256_max_epi32
.
Если вы начнете с границы выравнивания, то, надеюсь, вы прочитаете все строки кеша, к которым вы прикоснулись. И затем тот же шаблон доступа в выходных данных. (Таким образом, вы читаете от 2 до 6 последовательных строк кэша с шагом между блоками чтения / записи.)
Или, возможно, записать результаты tmp где-нибудь компактно (1 значение на сегмент в строке), прежде чем уничтожить больше кеш запись копий одного и того же элемента в каждый столбец. Но попробуйте оба пути; смешивание операций чтения и записи может позволить процессору лучше перекрывать работу и находить больше параллелизма на уровне памяти.
Используйте Аннотации .
Если вы отметите поля, которые вам нужно сравнить (независимо от того, являются ли они частными, вы все равно не потеряете инкапсуляцию и затем получите эти поля и сравните их. Это может быть следующее:
В классе, который нужно сравнить:
@ComparableField
private String field1;
@ComparableField
private String field2;
private String field_nocomparable;
И во внешнем классе:
public <T> void compare(T t, T t2) throws IllegalArgumentException,
IllegalAccessException {
Field[] fields = t.getClass().getDeclaredFields();
if (fields != null) {
for (Field field : fields) {
if (field.isAnnotationPresent(ComparableField.class)) {
field.setAccessible(true);
if ( (field.get(t)).equals(field.get(t2)) )
System.out.println("equals");
field.setAccessible(false);
}
}
}
}
Код не тестируется, но дайте мне знать, если поможет .
Это, вероятно, тоже не слишком хорошо, но это гораздо менее злобно (ИМХО), чем любая из двух предложенных вами альтернатив.
Как насчет предоставления одной пары геттер / сеттер, которая принимает поле числового индекса, а затем геттер / сеттер разыменовывает индексное поле на соответствующую переменную-член?
то есть:
public class MyClass {
public void setMember(int index, String value) {
switch (index) {
...
}
}
public String getMember(int index) {
...
}
static public String getMemberName(int index) {
...
}
}
А затем в вашем внешнем классе:
public void compareAndUpdate(MyClass a, MyClass b) {
for (int i = 0; i < a.getMemberCount(); ++i) {
String sa = a.getMember();
String sb = b.getMember();
if (!sa.equals(sb)) {
Log.v("compare", a.getMemberName(i));
b.setMember(i, sa);
}
}
}
Это, по крайней мере, позволяет вам сохранить все важные логика в исследуемом классе.
Я бы выбрал вариант 1, но я бы использовал getClass (). GetDeclaredFields ()
для доступа к полям вместо использования имен.
public void compareAndUpdate(MyClass other) throws IllegalAccessException {
for (Field field : getClass().getDeclaredFields()) {
if (field.getType() == String.class) {
Object thisValue = field.get(this);
Object otherValue = field.get(other);
// if necessary check for null
if (!thisValue.equals(otherValue)) {
log(field.getName() + ": " + thisValue + " <> " + otherValue);
field.set(other, thisValue);
}
}
}
}
Есть некоторые здесь есть ограничения (если я прав):
Общая мысль:
Создайте новый класс, объект которого принимает следующие параметры: первый класс для сравнения, второй класс для сравнения и списки имен методов получения и установки для объекты, в которые включены только интересующие методы.
Вы можете запросить с отражением класс объекта и оттуда его доступные методы. Предполагая, что каждый метод получения в списке параметров включен в доступные методы для класса, вы должны иметь возможность вызвать метод, чтобы получить значение для сравнения.
В общих чертах набросал что-то вроде (извиняюсь, если это не супер- идеально ... не мой основной язык):
public class MyComparator
{
//NOTE: Class a is the one that will get the value if different
//NOTE: getters and setters arrays must correspond exactly in this example
public static void CompareMyStuff(Object a, Object b, String[] getters, String[] setters)
{
Class a_class = a.getClass();
Class b_class = b.getClass();
//the GetNamesFrom... static methods are defined elsewhere in this class
String[] a_method_names = GetNamesFromMethods(a_class.getMethods());
String[] b_method_names = GetNamesFromMethods(b_class.getMethods());
String[] a_field_names = GetNamesFromFields(a_class.getFields());
//for relative brevity...
Class[] empty_class_arr = new Class[] {};
Object[] empty_obj_arr = new Object[] {};
for (int i = 0; i < getters.length; i++)
{
String getter_name = getter[i];
String setter_name = setter[i];
//NOTE: the ArrayContainsString static method defined elsewhere...
//ensure all matches up well...
if (ArrayContainsString(a_method_names, getter_name) &&
ArrayContainsString(b_method_names, getter_name) &&
ArrayContainsString(a_field_names, setter_name)
{
//get the values from the getter methods
String val_a = a_class.getMethod(getter_name, empty_class_arr).invoke(a, empty_obj_arr);
String val_b = b_class.getMethod(getter_name, empty_class_arr).invoke(b, empty_obj_arr);
if (val_a != val_b)
{
//LOG HERE
//set the value
a_class.getField(setter_name).set(a, val_b);
}
}
else
{
//do something here - bad names for getters and/or setters
}
}
}
}
While option 1 may be ugly, it will get the job done. Option 2 is even uglier, and opens your code to vulnerabilities you can't imagine. Even if you eventually rule out option 1, I pray you keep your existing code and not go for option 2.
Having said this, you can use reflection to get a list of the field names of the class, if you don't want to pass this as a static list to the method. Assuming you want to compare all fields, you can then dynamically create the comparisons, in a loop.
If this isn't the case, and the strings you compare are only some of the fields, you can examine the fields further and isolate only those that are of type String
, and then proceed to compare.
Hope this helps,
Yuval =8-)
с
Все поля имеют тип String, и я могу изменить код класса, владеющего полями, если требуется.
вы можете попробовать этот класс:
public class BigEntity {
private final Map<String, String> data;
public LongEntity() {
data = new HashMap<String, String>();
}
public String getFIELD1() {
return data.get(FIELD1);
}
public String getFIELD2() {
return data.get(FIELD2);
}
/* blah blah */
public void cloneAndLogDiffs(BigEntity other) {
for (String field : fields) {
String a = this.get(field);
String b = other.get(field);
if (!a.equals(b)) {
System.out.println("diff " + field);
other.set(field, this.get(field));
}
}
}
private String get(String field) {
String value = data.get(field);
if (value == null) {
value = "";
}
return value;
}
private void set(String field, String value) {
data.put(field, value);
}
@Override
public String toString() {
return data.toString();
}
магический код:
private static final String FIELD1 = "field1";
private static final String FIELD2 = "field2";
private static final String FIELD3 = "field3";
private static final String FIELD4 = "field4";
private static final String FIELDN = "fieldN";
private static final List<String> fields;
static {
fields = new LinkedList<String>();
for (Field field : LongEntity.class.getDeclaredFields()) {
if (field.getType() != String.class) {
continue;
}
if (!Modifier.isStatic(field.getModifiers())) {
continue;
}
fields.add(field.getName().toLowerCase());
}
}
этот класс имеет несколько преимуществ:
Вы говорите, что у вас есть геттеры и сеттеры для всех этих полей? Хорошо, тогда измените базовые данные из группы отдельных полей в массив. Измените все геттеры и сеттеры для доступа к массиву. Я бы создал постоянные теги для индексов, а не использовал числа для долгосрочной поддержки. Также создайте параллельный массив флагов, указывающих, какие поля должны быть обработаны. Затем создайте общую пару геттер / сеттер, которая использует индекс, а также геттер для флага сравнения. Примерно так:
public class SomeClass
{
final static int NUM_VALUES=3;
final static int FOO=0, BAR=1, PLUGH=2;
String[] values=new String[NUM_VALUES];
static boolean[] wantCompared={true, false, true};
public String getFoo()
{
return values[FOO];
}
public void setFoo(String foo)
{
values[FOO]=foo;
}
... etc ...
public int getValueCount()
{
return NUM_VALUES;
}
public String getValue(int x)
{
return values[x];
}
public void setValue(int x, String value)
{
values[x]=value;
}
public boolean getWantCompared(int x)
{
return wantCompared[x];
}
}
public class CompareClass
{
public void compare(SomeClass sc1, SomeClass sc2)
{
int z=sc1.getValueCount();
for (int x=0;x<z;++x)
{
if (!sc1.getWantCompared[x])
continue;
String sc1Value=sc1.getValue(x);
String sc2Value=sc2.getValue(x);
if (!sc1Value.equals(sc2Value)
{
writeLog(x, sc1Value, sc2Value);
sc2.setValue(x, sc1Value);
}
}
}
}
Я просто придумал это, я не тестировал это, так что могут быть ошибки в коде, но я думаю, что концепция должна работать.
Поскольку у вас уже есть геттеры. и сеттеры, любой другой код, использующий этот класс, должен продолжать работать без изменений. Если нет другого кода, использующего этот класс,
API JavaBeans предназначен для помощи в самоанализе. В той или иной форме он существует со времен Java версии 1.
Я бы также предложил решение, аналогичное тому, которое было предложено Альнитаком.
Если при сравнении требуется итерация полей, почему бы не отказаться от отдельных полей и не поместить данные в массив, HashMap или что-то подобное.
Затем вы можете получить к ним доступ программно, сравнить их и т. д. Если разные поля нужно обрабатывать и сравнивать по-разному, вы можете создать соответствующие вспомогательные классы для значений, которые реализуют интерфейс.
Затем вы можете просто сделать
valueMap.get("myobject").compareAndChange(valueMap.get("myotherobject")
или что-то в этом роде ...