Blackberry PIM, почему создание контактов такое медленное?

Следующий код, который я взял с форума Blackberry, занимает почти 26 минут для создания 2000 случайных контактов с использованием BB PIM API на наборе серии 8500. Кто-нибудь знает, почему это занимает так много времени или как повысить производительность создания контактов в адресной книге?

public static void testContactCreation() {
    ContactList contacts = null;
    try {
      contacts = (ContactList) PIM.getInstance().openPIMList(PIM.CONTACT_LIST, PIM.READ_WRITE);
    } catch (PIMException e) {
      // An error occurred
      return;
    }

    String arrSzCities[] = {"Birmingham", "Walsall", "Wolverhampton", "Banbury", "Bromsgrove", "Lichfield", "Balsall Heath",
        "West Bromich", "Smethwick", "Scott Arms", "Perry Barr", "Small Heath", "Acocks Green", "Great Barr",
        "Harborne", "Selly Oak", "Newtown", "Hockley", "Nuneaton", "Stafford", "Stoke", "Sandwell", "Brierly Hill",
        "Longbridge", "Sutton Coldfield", "Tamworth", "Coventry", "Rugby", "Hall Green", "Olton", "Dorridge",
        "Lapworth", "Shirley", "Wythall", "Warwick", "Dudley", "Barnt Green", "Tile Hill", "Berkswell", "Canley",
        "Yardley", "Yardley Wood", "Bordesley Green", "Cosely", "Four Oaks", "Erdington", "Aston", "Duddington"};

    String arrSzCountries[] = {"England", "Wales", "Scotland", "Northern Ireland", "Eire", "Spain", "France", "Italy",
        "Monaco", "Switzerland", "Austria", "Germany", "Lapland", "Estonia", "Hungary", "Slovakia", "Slovenia",
        "Czech Republic", "Latvia", "Holland", "Belgium", "Luxembourg", "Iceland", "Finland", "Denmark", "Norway"};

    String arrSzFamilyNames[] = {"SMITH", "JOHNSON", "WILLIAMS", "BROWN", "JONES", "MILLER", "DAVIS", "GARCIA", "RODRIGUEZ",
        "WILSON", "MARTINEZ", "ANDERSON", "TAYLOR", "THOMAS", "HERNANDEZ", "MOORE", "MARTIN", "JACKSON", "THOMPSON",
        "WHITE", "LOPEZ", "LEE", "GONZALEZ", "HARRIS", "CLARK", "LEWIS", "ROBINSON", "WALKER", "PEREZ", "HALL", "YOUNG",
        "ALLEN", "SANCHEZ", "WRIGHT", "KING", "SCOTT", "GREEN", "BAKER", "ADAMS", "NELSON", "HILL", "RAMIREZ", "CAMPBELL",
        "MITCHELL", "ROBERTS", "CARTER", "PHILLIPS", "EVANS", "TURNER", "TORRES", "PARKER", "COLLINS", "EDWARDS", "STEWART",
        "FLORES", "MORRIS", "NGUYEN", "MURPHY", "RIVERA", "COOK", "ROGERS", "MORGAN", "PETERSON", "COOPER", "REED",
        "BAILEY", "BELL", "GOMEZ", "KELLY", "HOWARD", "WARD", "COX", "DIAZ", "RICHARDSON", "WOOD", "WATSON", "BROOKS",
        "BENNETT", "GRAY", "JAMES", "REYES", "CRUZ", "HUGHES", "PRICE", "MYERS", "LONG", "FOSTER", "SANDERS", "ROSS",
        "MORALES", "POWELL", "SULLIVAN", "RUSSELL", "ORTIZ", "JENKINS", "GUTIERREZ", "PERRY", "BUTLER", "BARNES", "FISHER",
        "HENDERSON", "COLEMAN", "SIMMONS", "PATTERSON", "JORDAN", "REYNOLDS", "HAMILTON", "GRAHAM", "KIM", "GONZALES",
        "ALEXANDER", "RAMOS", "WALLACE", "GRIFFIN", "WEST",
        "COLE", "HAYES", "CHAVEZ", "GIBSON", "BRYANT", "ELLIS", "STEVENS", "MURRAY", "FORD", "MARSHALL", "OWENS",
        "MCDONALD", "HARRISON", "RUIZ", "KENNEDY", "WELLS", "ALVAREZ", "WOODS", "MENDOZA", "CASTILLO", "OLSON",
        "WEBB", "WASHINGTON", "TUCKER", "FREEMAN", "BURNS", "HENRY", "VASQUEZ", "SNYDER", "SIMPSON", "CRAWFORD", "JIMENEZ",
        "PORTER", "MASON", "SHAW", "GORDON", "WAGNER", "HUNTER", "ROMERO", "HICKS", "DIXON", "HUNT", "PALMER", "ROBERTSON",
        "BLACK", "HOLMES", "STONE", "MEYER", "BOYD", "MILLS", "WARREN", "FOX", "ROSE", "RICE", "MORENO", "SCHMIDT", "PATEL",
        "FERGUSON", "NICHOLS", "HERRERA", "MEDINA", "RYAN", "FERNANDEZ", "WEAVER", "DANIELS", "STEPHENS", "GARDNER", "PAYNE",
        "KELLEY", "DUNN", "PIERCE", "ARNOLD", "TRAN", "SPENCER", "PETERS", "HAWKINS", "GRANT", "HANSEN", "CASTRO", "HOFFMAN",
        "HART", "ELLIOTT", "CUNNINGHAM", "KNIGHT"};

    String arrSzFirstNames[] = {"MARY", "PATRICIA", "LINDA", "BARBARA", "ELIZABETH", "JENNIFER", "MARIA", "SUSAN", "MARGARET",
        "DOROTHY", "LISA", "NANCY", "KAREN", "BETTY", "HELEN", "SANDRA", "DONNA", "CAROL", "RUTH", "SHARON", "MICHELLE",
        "LAURA", "SARAH", "KIMBERLY", "DEBORAH", "JESSICA", "SHIRLEY", "CYNTHIA", "ANGELA", "MELISSA", "BRENDA", "AMY",
        "ANNA", "REBECCA", "VIRGINIA", "KATHLEEN", "PAMELA", "MARTHA", "DEBRA", "AMANDA", "STEPHANIE", "CAROLYN", "CHRISTINE",
        "MARIE", "JANET", "CATHERINE", "FRANCES", "ANN", "JOYCE", "DIANE", "ALICE", "JULIE", "HEATHER", "TERESA", "DORIS",
        "GLORIA", "EVELYN", "JEAN", "CHERYL", "MILDRED", "GERALD", "KEITH", "SAMUEL",
        "JAMES", "JOHN", "ROBERT", "MICHAEL", "WILLIAM", "DAVID", "RICHARD", "CHARLES", "JOSEPH", "THOMAS", "CHRISTOPHER",
        "DANIEL", "PAUL", "MARK", "DONALD", "GEORGE", "KENNETH", "STEVEN", "EDWARD", "BRIAN", "RONALD", "ANTHONY",
        "KEVIN", "JASON", "MATTHEW", "GARY", "TIMOTHY", "JOSE", "LARRY", "JEFFREY", "FRANK", "SCOTT", "ERIC", "STEPHEN",
        "ANDREW", "RAYMOND", "GREGORY", "JOSHUA", "JERRY", "DENNIS", "WALTER", "PATRICK", "PETER", "HAROLD", "DOUGLAS",
        "HENRY", "CARL", "ARTHUR", "RYAN", "ROGER", "JOE", "JUAN", "JACK", "ALBERT", "JONATHAN", "JUSTIN", "TERRY"};

    String arrSzEmailProviders[] = {"google", "yahoo", "wanadoo", "freemail", "aol", "yellowmellow", "redmail", "bt", "tiscali",
        "naims", "bulldog", "demon", "virgin", "sky", "orange", "vodaphone", "o2", "three", "britishgas", "npower",
        "britishtelecom", "royalmail", "parcelforce", "dhl", "usps", "ford", "rover", "fiat", "seat", "volvo", "bmw",
        "landrover", "jaguar", "warburtons", "kingsmill", "hovis", "walkers", "cadburys", "ironbru", "redbull", "jura"};

    String arrSzAlphas[] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
        "U", "V", "W", "X", "Y", "Z"};

    String arrSzStreetSuffixes[] = {"Road", "Street", "Crescent", "Close", "Way", "Mews", "Common", "Alley", "Common", "Grove",
        "Place", "Mill", "Manor", "Lane", "March", "Hill", "Park", "Passage", "Path", "Row", "Square", "Terrace", "View"};

    String arrSzStreetNames[] = {"High", "Station", "Main", "Park", "Church", "London", "Victoria", "Albert", "Green", "Manor",
        "Church", "Park", "Queens", "New", "Grange Road", "Kings Road", "North", "West", "South", "East", "Windsor",
        "Highfield", "Mill", "Alexander", "York", "St. John's", "Broad", "Springfield", "George", "Manchester", "Richmond",
        "School", "Stanley", "Chester", "Aghaloo", "Picadilly", "**bleep**", "Wooburn", "Crazies", "Valentia", "Luton", "Croydon",
        "Rookery", "Coronation", "Dawlish", "Tiverton", "Dartmouth", "Hubert", "Bristol", "Arley", "Grange", "Dale",
        "Serpentine", "Bournebrook", "University", "Holly", "Kitchener", "Millner", "Westminster", "Cherrington", "Gristhorpe",
        "Kensington", "Cartland", "Horatio", "Ethelbert", "Hornblower", "Hanky Panky", "Bewdley", "Acorn", "Berry", "Moor",
        "Brent", "Mungo Jerry", "Highbury", "Howell", "Tenbury", "Peacock", "Hartswell"};

    Random generator = new Random(1628434416);
    for (int i = 0; i < 2000; i++) {
      Contact contact = contacts.createContact();
      String[] addr = new String[contacts.stringArraySize(Contact.ADDR)];
      String[] szName = new String[contacts.stringArraySize(Contact.NAME)];

      // Family Name
      if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_FAMILY))
        szName[Contact.NAME_FAMILY] = arrSzFamilyNames[generator.nextInt(arrSzFamilyNames.length)];
      // First Name
      if (contacts.isSupportedArrayElement(Contact.NAME, Contact.NAME_GIVEN))
        szName[Contact.NAME_GIVEN] = arrSzFirstNames[generator.nextInt(arrSzFirstNames.length)];
      // Add name to contact
      contact.addStringArray(Contact.NAME, PIMItem.ATTR_NONE, szName);

      // Postcode (UK format)
      if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_POSTALCODE))
        addr[Contact.ADDR_POSTALCODE] =
            arrSzAlphas[generator.nextInt(arrSzAlphas.length)] + arrSzAlphas[generator.nextInt(arrSzAlphas.length)]
                + Integer.toString(generator.nextInt(99)) + Integer.toString(generator.nextInt(9)) + " "
                + arrSzAlphas[generator.nextInt(arrSzAlphas.length)] + arrSzAlphas[generator.nextInt(arrSzAlphas.length)];

      // Street and number
      if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_STREET))
        addr[Contact.ADDR_STREET] = Integer.toString(generator.nextInt(999)) + " "
            + arrSzStreetNames[generator.nextInt(arrSzStreetNames.length)]
            + " " + arrSzStreetSuffixes[generator.nextInt(arrSzStreetSuffixes.length)];

      // Locality
      if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_LOCALITY))
        addr[Contact.ADDR_LOCALITY] = arrSzCities[generator.nextInt(arrSzCities.length)];
      // Country
      if (contacts.isSupportedArrayElement(Contact.ADDR, Contact.ADDR_COUNTRY))
        addr[Contact.ADDR_COUNTRY] = arrSzCountries[generator.nextInt(arrSzCountries.length)];
      if (contacts.isSupportedField(Contact.ADDR))
        contact.addStringArray(Contact.ADDR, Contact.ATTR_HOME, addr);

      // Email address
      if (contacts.isSupportedField(Contact.EMAIL)) {
        contact.addString(Contact.EMAIL, Contact.ATTR_HOME | Contact.ATTR_PREFERRED, szName[Contact.NAME_GIVEN] + "." + szName[Contact.NAME_FAMILY] + "@" + arrSzEmailProviders[generator.nextInt(arrSzEmailProviders.length)] + ".com");
      }

      // Telephone numbers (work and home)
      String szTelHome = "";
      String szTelWork = "";
      for (int j = 0; j < 7; j++) {
        String szDigit = Integer.toString(generator.nextInt(9));
        szTelHome = szTelHome + szDigit;
        szTelWork = szDigit + szTelWork;
      }
      if (contacts.isSupportedField(Contact.TEL)) {
        contact.addString(Contact.TEL, Contact.ATTR_HOME, szTelHome);
      }
      if (contacts.isSupportedField(Contact.TEL)) {
        contact.addString(Contact.TEL, Contact.ATTR_WORK, szTelHome);
      }

      try {
        contact.commit();
      } catch (PIMException e) {
        // An error occured

      }
    }

    try {
      contacts.close();
    } catch (PIMException e) {
    }
  }

person Yasser    schedule 27.05.2011    source источник
comment
Зачем вообще вам нужно создавать 2000 контактов?   -  person Michael B.    schedule 27.05.2011
comment
Я думаю, это не имеет отношения к моему вопросу. Кстати, у меня в адресной книге не менее 2000 контактов, поэтому я не считаю это необычным или необычным.   -  person Yasser    schedule 27.05.2011
comment
Вы уверены, что долго занимает добавление контакта, а не создание случайных контактов?   -  person jprofitt    schedule 31.05.2011
comment
Да, почти наверняка, но я хотел бы, чтобы меня доказали, что он неправ :)   -  person Yasser    schedule 31.05.2011
comment
Возможно, попробуйте закомментировать всю логику в цикле и просто попросите его распечатать строки с подробностями того, что вы хотите добавить. Если это займет много времени, вы поймете, где виноват!   -  person jprofitt    schedule 01.06.2011
comment
Я могу подтвердить, что commit () занимает большую часть времени выполнения. Я создал вектор для сохранения контрактов и переместил фиксацию из основного цикла в его собственный цикл. Цикл, который создает контракты, занимает всего пару секунд, цикл, который вызывает фиксацию контрактов в векторе, занимает 20+ минут. Я пытаюсь выяснить, есть ли способ выполнить пакетную фиксацию, как это можно сделать с помощью PersistentStore.   -  person eSniff    schedule 04.06.2011
comment
Я так и не нашел способа выполнить пакетную фиксацию с помощью объекта PIM. Возможно, было бы быстрее записать этот PIMList в FileStream и читать его оттуда.   -  person eSniff    schedule 07.06.2011


Ответы (1)


Хм .. 26 минут для 2000 контактов означает 780 мс на один контакт.

1). Не могли бы вы проверить, contact.commit(); здесь не самый трудоемкий звонок? Вы можете сделать это сравнительно точно с помощью чего-то вроде этого:

long timeSpentOnCommits; // defined somewhere at a top level
...
long start = System.currentTimeMillis();
contact.commit();
long taken = System.currentTimeMillis() - start;
timeSpentOnCommits += taken;
...
// then after the all contacts have been added you can get 
// an average commit time:
long timePerOneCommit = timeSpentOnCommits / 2000;
// view the got value in a `Dialog` or some logging

Если это занимает большую часть времени, я не думаю, что вы сможете это улучшить.

2). Другая идея - в цикле for вы создаете слишком много String объектов, поэтому это вынуждает ОС слишком часто вызывать сборку мусора (что отнимает много времени).

Вместо этого используйте StringBuffer. Так что вместо

addr[Contact.ADDR_POSTALCODE] =
    arrSzAlphas[generator.nextInt(arrSzAlphas.length)]
    + arrSzAlphas[generator.nextInt(arrSzAlphas.length)]
    + Integer.toString(generator.nextInt(99)) 
    + Integer.toString(generator.nextInt(9)) 
    + " "
    + arrSzAlphas[generator.nextInt(arrSzAlphas.length)]
    + arrSzAlphas[generator.nextInt(arrSzAlphas.length)];

использовать это:

addr[Contact.ADDR_POSTALCODE] = new StringBuffer()
    .append(arrSzAlphas[generator.nextInt(arrSzAlphas.length)])
    .append(arrSzAlphas[generator.nextInt(arrSzAlphas.length)])
    .append(generator.nextInt(99))
    .append(generator.nextInt(9))
    .append(' ')
    .append(arrSzAlphas[generator.nextInt(arrSzAlphas.length)])
    .append(arrSzAlphas[generator.nextInt(arrSzAlphas.length)])
    .toString();

Обратите внимание, что StringBuffer.append() перегружен для любого примитивного типа, поэтому он может принимать целые числа и символы напрямую без необходимости преобразования в объекты String.

Такой же подход следует использовать для генерации телефонных номеров.

3). Незначительные улучшения скорости могут быть получены путем извлечения всех повторяющихся вызовов из цикла for. Например, просто посчитайте, сколько раз вы вызываете arrSzAlphas.length (2000 итераций * 4 вызова на итерацию = 8000 раз!), В то время как вы можете просто вызвать его ОДИН РАЗ перед циклом и сохранить его в конечной локальной переменной, видимой из цикла. То же самое и для набора contacts.isSupportedXXXX вызовов - вы не должны вызывать его снова и снова на всех итерациях, просто вызывайте его один раз перед запуском цикла.

person Vit Khudenko    schedule 31.05.2011
comment
Когда я задал вопрос, я знал, что вызов commit () занимает большую часть времени, поэтому я просил объяснить, почему это так и можно ли это улучшить. Все остальные улучшения мелкие или несущественные. - person Yasser; 07.06.2011
comment
@Yasser. Хорошо, я думаю, вам следовало указать это более явным образом, сузившись до вызова contact.commit(). - person Vit Khudenko; 07.06.2011
comment
Да, извините за это. Я, очевидно, заинтересован в сокращении времени с 26 минут до 5 минут, а не с 26 минут до 25 минут 58 секунд :) - person Yasser; 07.06.2011