C#; Working code--needs review Techies--
This routine does more once the channels + the subsets of existing batch arrays are re-distributed for processing. However, the success of that will only work as well as the initial splits. The threshold value is dubbed here, but it will come from app.config as configurable setting. Obviously the jagged string array is dubbed for review purposes. The real values will be coming from another routine and will frequently have counts > 100000. The 3 lines of comments where one will do is a product of formatting the code for StackExchange.

Please review what's here.

   #region Channel Assignment Testing

    static void ChannelAssign()
    {
        int THRESHOLD = 1;  

        string[] batch = new string[] 
            { "item1", "item2", "item3", "item4","item5","item6","item7" };
        int batchcnt = batch.Count();
        int subsetqty; // subset batch item quantity
        string[][] subsets; // Split extension returns these values
        int channelidx; // index for channels back from Split


        if (THRESHOLD != 0) //avoid accidental division by 0.
        {
            float channels = batchcnt/THRESHOLD;
            if (channels &lt; 1) // can handle all items in existing batch based on 
                              // threshold setting.
            {
                channels = 1; // dub as a single channel
                subsetqty = batchcnt; // process all batch items in batch 
                channelidx = 1; // dub index for a single channel
                subsets = batch.Split(batchcnt); // ship the batchcount 
                                                 // to split routine.
            }
            else // we need at least 2 channels; round up from float 
                 // and decide how many.
            {
              channels =  (int)Math.Round(channels, 
                            MidpointRounding.ToEven); //determines channel# estimate
              subsetqty = batchcnt/(int)channels; // estimates # of 
                                                  // existing batch items to 
                                                  // place in each subset
              subsets = batch.Split(subsetqty); // actual subsets of batches returned
              channelidx = subsets.GetLength(0); //gets actual channel# assigned 
                                                 // by split

            }

            //distribute contents of batch into subsets for channel consumption
            for (int channel = 0; channel &lt; channelidx; channel++)
            {
                for(int i = 0; i &lt; subsets[channel].Length; i++)
                {
                    Console.WriteLine(" Channel:" + channel.ToString() + " ItemName: 
                      {0} ", subsets[channel][i]);
                }
            }
        }
        else
        {
            Console.WriteLine("Threshold value set to zero. This is an 
                                invalid value. Please set THRESHOLD.");
        }

    }

    #endregion


Split Extension

        public static T[][] Split&lt;T&gt;(this T[] arrayIn, int length)
        {
            bool even = arrayIn.Length % length == 0;
            int totalLength = arrayIn.Length / length;
            if (!even)
                totalLength++;

            T[][] newArray = new T[totalLength][];
            for (int i = 0; i &lt; totalLength; ++i)
            {
                int allocLength = length;
                if (!even &amp;&amp; i == totalLength - 1)
                    allocLength = arrayIn.Length % length;

                newArray[i] = new T[allocLength];
                Array.Copy(arrayIn, i * length, newArray[i], 0, allocLength);

            }

            return newArray;
        }
I like the formatting, use of white space and tabs.

I'm not sure what THRESHOLD is supposed to represent or where its set, but in the example, I'd make it a const.

I would do the check for 0 right below the assignment:

if (THRESHOLD == 0)
{
    ...

    return;
}


This will un-nest the main logic of your function and catch the error before any processing is done.

The logic should be moved out into their own functions:

var subsets = (channels &lt; 1) ? ProcessWholeList(...) : ProcessPartialList(...);


This will better portray then intention of the logic and remove most of the unimportant variables out of the function cleaning it up quite a bit.

I like that you have created an extension to do the split, not many people think of that.

I would change the bool even ... into a check for odd numbers.  That what you could change the 

if (!even)


to

if (odd)
{
    ....
}


Again, expresses the intent a little better.  I would also either move the assignment to right above the check.

This assignment:

int allocLength = length;
if (!even &amp;&amp; i == totalLength - 1)
    allocLength = arrayIn.Length % length;


Should be changed to:

var allocLength = (!even &amp;&amp; i == totalLength - 1) ? arrayIn.Length % length : length;


There are just a few simple changes that will clean it up quite a bit.  I hope this is a good start and gives you some ideas.

I have another question, is there a reason why you are using a 2 dimensional array rather than one of the build in IEnumerables (i.e. HashTable)?  I think for performance purposes, the two dimensional array would be the slowest way of doing it.